Skip to main content
Version: 1.7.0

TACO 应用开发技术手册

一、前言

TACO,全称为 Topsfuture AI Computing Optimized,是一个专为边缘计算场景打造的高性能、全栈式 AI 应用开发平台。我们的目标是提供一套从模型开发、代码编译到设备端部署运行的端到端优化解决方案,帮助开发者高效地构建并落地各类边缘 AI 应用。

1.1 概述

TACO 的生态系统在设计上清晰地划分为两个主要部分:Host(开发端)Device(设备端)

Host(开发端)

  • 运行在开发者 PC 或服务器上,基于 Docker 环境
  • 提供完整的开发与编译工具链,包括:
    • taWorkshop:用于交叉编译应用程序
    • taNNTC:用于 AI 模型转换优化
  • 所有开发阶段的工作均在此完成

Device(设备端)

  • 指最终部署应用的 TACO 硬件平台
  • 搭载经过深度优化的 AI Stack 软件栈
  • 负责高效运行应用程序和 AI 模型

这种"开发与运行分离"的模式,确保了开发者可以在熟悉的 x86 环境下进行高效开发,同时保证了应用在目标设备上运行时能获得最佳的性能和兼容性。

1.2 框架架构(AI Stack)

TACO 的核心竞争力在于其设备端的 AI Stack 软件栈。该软件栈采用分层设计,实现了从底层硬件驱动到上层应用接口的全面优化,确保每一层都能高效协同工作。

alt text

1. 应用层

这一层是开发的具体业务应用,例如:

  • 智能安防
  • 质量检测
  • 智慧零售

应用代码会调用下层框架提供的 API 来实现所需功能。

2. 框架层

该层面向快速应用开发,提供了一系列与开源社区标准兼容的高级 API,封装了复杂的底层实现,是开发者最常直接交互的层次。

主要组件包括:

  • taFFmpeg:硬件加速的多媒体框架,用于高效处理音视频的编解码和推拉流任务
  • taOpenCV:经过 RISC-V Vector(RVV)硬件加速的计算机视觉库,提供了丰富的通用图像处理算法接口

3. 中间件层

这是 TACO 平台的核心,负责连接上层应用与底层硬件,提供核心功能引擎和硬件抽象。

核心组件包括:

  • taRuntime:AI 推理引擎,负责加载、管理并高效执行 AI 模型,是整个 AI Stack 的核心
  • taCV:硬件 CV 加速库,提供对专用图像处理单元(SPP)的直接访问接口,用于极致性能的图像预处理
  • taSys:内存管理核心,是平台高性能的基石。它负责管理硬件单元所需的特殊内存,是实现"零拷贝"数据流转的关键

4. 内核层

该层是整个软件栈的基础,由以下组件组成:

  • Linux 内核
  • 硬件驱动程序

负责最基础的资源管理和对硬件的直接控制。

通过这套分层架构,TACO 实现了灵活性与高性能的统一。开发者既可以利用框架层快速构建应用,也可以在性能瓶颈点深入中间件层进行精细优化,从而满足不同场景下的开发需求。

二、核心基础:内存管理

2.1 物理内存布局(DDR 整体划分)

内存分配是应用开发的基础,本章主要介绍 TACO 的内存管理机制。

以板载 16GiB DDR 为例,SDK 将总共 16384MiB 地址空间划分成 3 个工作区:

内存区域物理地址范围容量管理方式
Linux 系统内存区0x1,0000,0000 ~ 0x1,FFFF,FFFF4GiB自动管理,不可配置
媒体专用内存区0x2,0000,0000 ~ 0x3,FFFF,FFFF8GiB用户可配置
NPU 专用内存区0x4,0000,0000 ~ 0x4,FFFF,FFFF4GiB用户可配置

各内存区使用逻辑

  • Linux 系统内存区:应用程序运行所需的进程、线程空间、堆空间(heap)都位于此区域。
  • 媒体专用内存区:主要用于缓存媒体数据,特指以帧为单位的音视频数据。
  • NPU 专用内存区:主要用于加载神经网络模型,以及在执行推理过程中缓存中间数据和推理结果。

2.2 内存域模型与访存特性

SDK 在设计上将 DDR 内存按照用途划分为三个域(domain):

系统域(System Domain)

  • 管理方式:由 Ubuntu 系统直接管理。
  • 用途:为操作系统本身以及各类应用程序提供运行环境和业务内存。
  • 示例:系统调用 malloc() 接口返回的内存即位于系统域。

媒体域(Media Domain)

  • 管理方式:由媒体模块(taSys)直接管理。
  • 用途:主要用于存储音视频编解码业务所涉及的数据,包括压缩码流数据和解压后的帧数据等。

NN 域(Neural Network Domain)

  • 管理方式:由 NPU 驱动直接管理。
  • 用途:主要用于存储神经网络(NN)业务所涉及的数据,包括网络模型的指令流和权重数据,以及 NPU 工作时产生的临时数据等。

2.2.1 访存特性差异

上述三个域除了名称不同之外,本质差异在于数据的存储方式和访存方式不同:

  • EA65xx 芯片的 CPU 使用虚拟地址访问 DDR,这种虚拟地址与 NPU 硬件使用的虚拟地址不同。
  • 两者使用各自独立的内存分配器。
  • 虚拟地址在逻辑上是连续的,但是虚拟地址所对应的物理地址一般并不连续,而是以页为单位随机分布在所属的域上。
  • 如果数据存储在系统域,则除了 CPU 外其它硬件难以寻址,除非该硬件也支持页表,可以逐页建立地址映射关系。
系统域访存特性
  • EA65xx 芯片的 CPU 配备了 MMU(Memory Management Unit)单元。
  • 运行在 CPU 上的程序使用虚拟地址访问 DDR 内存(称为 CPU 虚拟地址或系统域虚拟地址)。
  • 虚拟地址对应的物理地址以页(每页 4KB)为单位随机分布在系统域上。
  • CPU 访问内存需要通过 MMU 做地址映射。
  • CPU 以外的主控单元难以访问系统域 buffer 的数据。
媒体域访存特性
  • EA65xx 芯片中的媒体单元(包括视频编解码和 JPEG 编解码器)均没有配备 MMU 单元。
  • 媒体单元只能通过物理地址访问 DDR 内存,并且要求一帧数据必须是连续存储的(contiguous)。
  • SDK 规划了媒体域内存区专门用于存储音视频数据。
  • 媒体驱动(taSys)提供了将物理地址映射为 CPU 虚拟地址的接口。
  • NPU 驱动提供了将物理地址映射为 NPU 虚拟地址的接口。
NN 域访存特性
  • EA65xx 芯片的 NPU 配备了 MMU 单元。
  • NPU 硬件使用虚拟地址访问 DDR 内存(称为 NPU 虚拟地址或 NN 域虚拟地址)。
  • NPU 虚拟地址与 CPU 虚拟地址无关。

2.2.2 数据访问解决方案

如果待推理的图像实际存储在系统域,NPU 不能使用 CPU 虚拟地址进行访问,SDK 支持两种解决方法:

方法一:拷贝方法
  • 实现:在 taRuntime 接口内部将图像数据从系统域复制到 NN 域 buffer中。
  • 访问方式:NPU 通过 NN 域虚拟地址访问。
  • 缺点:消耗 CPU 和 DDR 带宽资源。
  • 推荐度:不推荐作为正式产品方案。
方法二:映射方法
  • 实现:在 taRuntime 接口内部将系统域虚拟地址以内存页为单位逐页映射为 NN 域虚拟地址。
  • 缺点:当图像比较大时,操作耗时较多(约 20ms)。
  • 推荐度:不推荐作为正式产品方案。
推荐方案

根据以上讨论,图像不宜存储在系统域内存区,而应存储在媒体域内存区。taRuntime 接口支持外部提供待推理图像的物理地址,接口内部将物理地址映射为 NN 域虚拟地址,这个操作开销较小。

2.3 taSys 内存介绍

2.3.1 taSys 简介与公共缓存池

  • EA65xx 芯片上的硬件编解码单元和视频处理单元只能使用物理地址访问 DDR 内存。
  • 使用 taFFmpeg / taOpenCV 库提供的硬件加速功能时,相关接口最终只能使用 taSys 模块分配的内存,不能使用 malloc() 接口分配的系统域内存。
  • taSys 提供 alloc 接口,以便用户申请连续的物理内存块。
  • SDK 中的 taSys 模块提供了配置和创建公共缓存池的接口。
  • 用户可以为每个公共缓存池配置一批缓存块(VB,Video Buffer)。

⚠️ 注意:

  • 应用程序应在初始化阶段创建好各业务所需的缓存池,业务一旦开始运转,缓存池的配置就不能轻易变化。

2.4 高性能内存访问策略

2.4.1 关于零拷贝

PC 平台与 EA65xx 平台差异
平台内存使用方式
PC 平台通过 malloc() 从操作系统申请 buffer,加载数据后提交给 FFmpeg 进行编解码
EA65xx 平台由于硬件约束,对 buffer 的使用方式需要变化
硬件访问限制

EA65xx 芯片的硬件单元无法直接访问系统域 buffer,因此:

  • 如果输入数据位于系统域,SDK 必须把数据拷贝到媒体域才能交给硬件处理。
  • 这种拷贝会消耗 CPU 和 DDR 资源。
零拷贝(Zero Copy)方案

SDK 对 FFmpeg 使用的 AVFrameAVPacket 等结构体进行了扩展:

  • 使用硬件加速功能时,用户可以提供媒体域 buffer 的物理地址以便硬件直接处理。
  • 如果用户提供的是系统域 buffer 的虚拟地址,taFFmpeg 接口内部会自动申请媒体域 buffer 并执行一次拷贝。
性能对比

两种工作方式在以下方面存在区别:

  • DDR 带宽消耗
  • CPU 负载
  • 接口延迟
  • 最高帧率
  • buffer 数量

推荐:建议用户优先采用 零拷贝方式 以获得最佳性能。

三、核心神经网络推理引擎(taRuntime)

3.1 taRuntime 概述

关于网络模型的工作大致可以分为模型导入阶段和运行时(Runtime)阶段,本文档主要讨论运行时阶段,也就是与在板端执行推理有关的问题。

taRuntime 是 EA65xx 芯片 SDK 的一个重要组成模块,它在板端提供了一组 C 语言编程接口(API),用于支持板端应用程序基于 EA65xx NPU 硬件完成网络模型推理任务。

为了帮助您理解和使用 taRuntime 模块的接口,本章就一些重要概念和工作原理进行说明。由于篇幅限制,本章只重点讲解与接口设计和使用相关的内容,对于通识性的概念将不做展开说明。

taRuntime 提供的接口功能覆盖:

  • 网络模型加载
  • 模型信息提取
  • 输入输出配置
  • 执行模型推理

3.2 关于 Buffer Pool

如前所述,对于 NPU 推理而言,不论输入图像是 CPU 虚拟地址还是物理地址都需要映射成 NPU 虚拟地址才能被 NPU 使用,而映射过程总是要有一定开销的。

Pool/VB 机制

SDK 的媒体驱动(taSys)提供了一套 Pool / VB 机制(Video Buffer Pool),通过循环复用 Pool 中提供的 VB(Video Frame Buffer)可以减少内存分配和地址映射的次数,从而降低软件延迟。

工作原理

  • taRuntime 接口内部维护了一个查找表。
  • 当外部提供图像的方式为物理地址时,接口内部首先试图从查找表获取对应的 NPU 虚拟地址。
  • 只有查表失败时才会发起地址映射操作。
  • 当外部提供的物理地址源于 Pool / VB 机制时,查表成功的概率极大,可以显著压缩地址管理开销。

3.3 关于前处理

前处理定义

前处理(Pre-processing)指的是在执行模型推理之前,对输入数据(图像)进行以下操作,使其符合网络模型第一层对数据格式的要求:

  • 缩放(Resize)
  • 裁切(Crop)
  • 颜色空间变换(Color Space Conversion)
  • 存储格式和精度格式变换

前处理方案

硬件加速方案

  • SDK 提供的 taCV 和 taOpenCV 模块提供了丰富的接口,支持大多数常见的前处理需求。
  • 比如,taCV 模块提供基于芯片硬件单元完成的缩放、裁切、颜色空间变换等操作。

软件处理方案

  • 对于某些芯片硬件单元不支持的操作,其算子是基于 CPU 算力实现的。
  • 以 RGB24 图像转 INT8 张量格式为例,涉及像素位置重排和减 offset 操作,在 taOpenCV 中这类算子基于 CPU 算力实现,耗时较长。

优化建议

模型移植优化

建议在模型移植阶段就把这类算子合并到网络模型中,推理时利用 NPU 算力完成处理。

PPU 单元利用

  • EA65xx 芯片的 NPU 配属了 PPU(Pre-processing Unit)单元。
  • PPU 提供了一定的算子可编程能力。
  • 原厂可以基于 PPU 硬件开发新的算子并通过 taCV 模块暴露给用户使用。

⚠️ 注意:

  • NPU 单元与 PPU 单元只能分时工作,使用 PPU 算子会占用 NPU 算力。

3.4 关于后处理

后处理定义

后处理(Post-processing)一般是指对 NPU 输出的推理结果进行过滤从而获得最终结果。

典型后处理任务

以 YOLO 系列模型为例,典型的后处理任务包括:

  1. 从上万个待处理结果中去除冗余的检测框。
  2. 删除置信度过低的检测框。
  3. 对幸存结果进行排序获得 top-k 个候选框。
  4. 根据预设的阈值筛选出最终的检测框。
  5. 将类别索引 ID 映射回人类可理解的类别标签。

后处理实现方式

CPU 处理原因

  • 涉及大量的复杂逻辑处理,运算性质不利于硬件实现。
  • 算法更新迭代速度快,后处理需求经常变化。

推荐方案

  • 后处理步骤主要借助 CPU 算力完成。
  • taOpenCV 提供了丰富的专用算子。
  • 用户可以利用 taOpenCV 接口实现大部分后处理操作。

3.5 关于多进程多线程

本模块的接口支持在多个进程、多个线程中调用,具体工作逻辑如下:

进程工作流程

对于一个进程来说,其工作流程可以分成三个阶段:

  1. 初始化阶段
  2. 推理阶段
  3. 反初始化阶段

一般做法是在推理阶段创建多个工作线程,每个线程负责一路视频流的推理。

多进程支持

当存在多个进程时:

  • 为了避免在进程间协调接口调用时序,SDK 允许每个进程都独立地调用初始化和反初始化接口。
  • 实际上只有一次调用会实际生效(触发硬件初始化/反初始化流程)。
  • 其它无效的调用会被忽略,但不返回错误。

多线程任务管理

在一个进程内部:

  • 用户调用接口时需要提供一个 context 结构体。
  • context 的作用是帮助接口识别任务来源。
  • 来自多个线程的任务最终会被推送到由内核驱动维护的任务队列。
  • 硬件按照先到先服务的原则依次处理队列中的任务。

3.6 taRuntime 模块开发

NN 推理概念

NN 推理(Neural Network Inference)指的是在开发板上运行一个 AI 推理程序,核心流程包括:

  1. 从 Linux 文件系统加载网络模型到内存中。
  2. 提取推理指令流和权重参数。
  3. 分配内存和计算资源。
  4. 提交推理任务到 taRuntime。
  5. 触发 EA65xx 芯片的 NPU 运行模型。
  6. CPU 对 NPU 推理结果进行后处理。
  7. 输出检测/识别结果。

开发流程

  1. 模型准备:请算法工程师提供能在 EA65xx 板端运行的模型文件。
  2. 程序开发:应用开发工程师参考 sample 编写程序。
  3. 接口调用:调用 taRuntime 库的 API 接口加载和运行模型文件。
  4. 前后处理:调用其它 SDK 模块提供的 API 接口获取图像及进行前后处理。
  5. 部署调试:将编译好的程序拷贝到板端调试运行。

示例代码

// taRuntime API 基本使用流程

// 初始化
ta_runtime_init();

// 创建上下文
ta_runtime_context context;

// 加载模型:从文件系统加载到系统内存,再读入 NN 域
ta_runtime_load_model_from_file(&context, file_path, 0);

// 设置模型输入
taconn_input_t input;
ta_runtime_set_input_cva(&context, input_count, input);

// 设置模型推理的输出 buffer
taconn_buffer_t *output;
ta_runtime_create_buffer(&context, output_size, output);
ta_runtime_set_output(&context, output_count, output);

// 运行网络
ta_runtime_run_network(&context);

// 确保 CPU 读到最新数据
ta_runtime_invalidate_buffer(&context, output);

// 读取 buffer 数据后,释放内存
ta_runtime_destroy_buffer(&context, output);

四、多媒体应用开发

4.1 概述

本文档所述的多媒体框架是指 TACO SDK 中提供的 taCV 库以及以 FFmpeg、OpenCV、OpenBLAS 为代表的开源框架/库。这些开源框架/库的部分核心功能已经在 EA65xx 平台上实现了硬件加速,主要功能覆盖:

  • 视频解码(H.264、H.265)
  • 视频编码(H.264)
  • 静态图像解码(JPEG)
  • 静态图像编码(JPEG)
  • 视频处理
  • 矩阵和数组运算

用户可以根据自己的习惯选择合适的框架/库,从而快速实现产品功能开发。

taCVtaFFmpegtaOpenCV 这几套接口在功能上互有交叉但各有侧重:

  1. taCV 库:提供了所有能用芯片硬件加速的功能接口,包括基于芯片硬件 IP 实现的 JPEG 编解码功能和常用视频处理功能。
  2. taFFmpeg 框架:提供了获取视频流和流转发的协议,除了原有的基于 CPU 算力实现的视频/图像编解码功能之外,还提供了基于芯片硬件能力实现的视频/图像编解码接口。
  3. taOpenCV 框架:除了原有的基于 CPU 算力提供的图像编解码和图像处理功能之外,还通过 taCV 提供了 JPEG 硬件编解码功能和部分视频处理功能。

4.2 视频流输入处理

4.2.1 硬件规格介绍

视频解码器

EA65xx 芯片提供的硬件解码器参数规格为:

  • 支持格式:AVC/H.264 Baseline/Main/High/High10 Profile,SVC-T,HEVC/H.265 Main 10 Profile
  • 分辨率范围:最小 128×128,最大 4096×2160(4K DCI)
  • 解码能力:支持 16 路 FullHD@30fps(或 4 路 4K@30fps)实时解码
视频编码器

EA65xx 芯片提供的硬件编码器参数规格为:

  • 支持格式:H.264 Baseline/Main/High/High 10 Profile
  • 分辨率范围:最小 128×128,最大 2048×1080(2K DCI)
  • 编码能力:支持 2 路 FullHD@60fps 实时编码
静态图像编解码

EA65xx 芯片支持 JPEG Baseline & Progressive 格式的硬件编/解码加速:

  • JPEG 解码
    • 分辨率范围:最大 32768×32768
    • 解码性能:不低于 FullHD@480fps
  • JPEG 编码
    • 分辨率范围:最小 96×32,最大 8192×8192
    • 编码性能:不低于 2 路 FullHD@60fps

📝 注意:

  • 对于 JPEG Baseline & Progressive 以外的图片格式(包括 Bmp、Png、JPEG2000 等),taOpenCV 接口使用 CPU 算力进行软件编解码。
地址对齐要求

视频编解码器、静态图像编解码器对输入输出 buffer 都有地址对齐要求,buffer 首地址应满足 4KB 对齐

4.2.2 使用 taFFmpeg 拉取视频流

taFFmpeg 支持多种协议和格式的推流和拉流操作。当使用 taFFmpeg 库进行拉流时,需要使用到 libavformatlibavcodec 库中提供的接口。

核心 API 接口
API 接口功能描述
avformat_network_init()初始化网络组件
avformat_open_input()打开输入 URL(如 RTMP、RTSP 地址),获取格式上下文
avformat_find_stream_info()读取数据并解析,获取输入流的详细信息
av_find_best_stream()在输入文件中查找最佳的音频和视频流
avcodec_find_decoder()根据流的编解码器 ID 查找适当的解码器
avcodec_alloc_context3()为解码器创建上下文
avcodec_parameters_to_context()将流参数复制到解码器上下文
avcodec_open2()打开解码器
av_frame_alloc()分配 AVFrame 结构体,用于存储解码后的帧
av_packet_alloc()分配 AVPacket 结构体,用于存储压缩码流数据
av_read_frame()从输入流中读取一个完整的数据包
avcodec_send_packet()将数据包发送到解码器
avcodec_receive_frame()从解码器接收解码后的帧
avcodec_free_context()释放解码器上下文
av_frame_free()释放 AVFrame
av_packet_free()释放 AVPacket
avformat_close_input()关闭输入流并释放相关资源
示例代码(使用 h264_taco 解码器)

以下示例代码使用 h264_taco 解码器,通过循环调用 avcodec_send_packet()avcodec_receive_frame() 接口完成对 MP4 视频文件的解码。

#include <iostream>
#include <unistd.h>

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/avutil.h>
}

// RTMP 流地址示例
#define RTMP_ADDR "rtmp://127.0.0.1:1935/live/1234"

int main(int argc, char* argv[]) {
int res;
FILE *fp = fopen("result.yuv", "w+b");
if (!fp) {
std::cerr << "Failed to open output file" << std::endl;
return -1;
}

const char* input_file = "./input.mp4"; // 可替换为 RTMP_ADDR

AVFormatContext* format_ctx = nullptr;
res = avformat_open_input(&format_ctx, input_file, nullptr, nullptr);
if (res < 0) {
std::cerr << "Failed to open input file" << std::endl;
fclose(fp);
return -1;
}

res = avformat_find_stream_info(format_ctx, nullptr);
if (res < 0) {
std::cerr << "Failed to find stream info" << std::endl;
avformat_close_input(&format_ctx);
fclose(fp);
return -1;
}

// 检测视频流索引
int video_stream_index = -1;
for (unsigned int i = 0; i < format_ctx->nb_streams; i++) {
if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_stream_index = i;
break;
}
}

if (video_stream_index == -1) {
std::cerr << "No video stream found" << std::endl;
avformat_close_input(&format_ctx);
fclose(fp);
return -1;
}

const AVCodec* codec = avcodec_find_decoder_by_name("h264_taco");
if (!codec) {
std::cerr << "Codec h264_taco not found" << std::endl;
avformat_close_input(&format_ctx);
fclose(fp);
return -1;
}

AVCodecContext *codec_ctx = format_ctx->streams[video_stream_index]->codec;
if (!codec_ctx) {
std::cerr << "Failed to get codec context" << std::endl;
avformat_close_input(&format_ctx);
fclose(fp);
return -1;
}

res = avcodec_open2(codec_ctx, codec, nullptr);
if (res < 0) {
std::cerr << "Failed to open codec" << std::endl;
avformat_close_input(&format_ctx);
fclose(fp);
return -1;
}

AVFrame* frame = av_frame_alloc();
AVPacket* packet = av_packet_alloc();
size_t y_size, uv_size;

while (true) {
// 释放未使用的 YUV buffer
if (frame) {
av_frame_free(&frame);
frame = NULL;
}

if (av_read_frame(format_ctx, packet) < 0)
break;

if (packet->stream_index == video_stream_index) {
int response = avcodec_send_packet(codec_ctx, packet);
if (response < 0) {
std::cerr << "Error sending packet for decoding" << std::endl;
break;
}

while (response >= 0) {
// 准备 AVFrame 结构体(不分配 YUV buffer)
if (frame == NULL) {
frame = av_frame_alloc();
}

response = avcodec_receive_frame(codec_ctx, frame);
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
break;
} else if (response < 0) {
std::cerr << "Error during decoding" << std::endl;
break;
}

y_size = frame->width * frame->height;
uv_size = y_size / 2;
fwrite(frame->data[0], 1, y_size, fp);
fwrite(frame->data[1], 1, uv_size, fp);
}
}

av_packet_unref(packet);
av_free_packet(packet);
}

fclose(fp);
av_frame_free(&frame);
av_packet_free(&packet);
avformat_close_input(&format_ctx);

return 0;
}
代码要点说明
  1. av_read_frame() 接口:内部封装了 buffer 管理行为。当试图读取数据包时,如果 AVPacket 结构体未初始化或大小不足,接口内部会自动调用 av_new_packet() 重新分配数据缓存。SDK 对该接口进行了扩展,使其在媒体域上分配内存,能够同时被 CPU 和编解码硬件访问,每帧可节省一次拷贝操作。
  2. av_frame_alloc() 接口:仅创建结构体所需的存储空间,不分配 YUV buffer。正常情况下,avcodec_receive_frame() 会自动从内部缓存池获取 YUV buffer。特殊情况可显式调用 av_frame_get_buffer() 分配。
  3. API 演进:早期 FFmpeg 使用 avcodec_decode_video2() 接口,从 FFmpeg 3.x 开始推荐使用 avcodec_send_packet()avcodec_receive_frame() 这对新接口。
传统接口示例(已过时)

📝 注意:

  • 以下为使用旧版 avcodec_decode_video2() 接口的示例,仅作参考。
#include <iostream>
#include <unistd.h>

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/avutil.h>
}

int main(int argc, char* argv[]) {
// ... 初始化代码与前面示例类似

AVFrame* frame = av_frame_alloc();
AVPacket packet;
int got_picture;
size_t y_size, uv_size;

while (av_read_frame(format_ctx, &packet) >= 0) {
if (packet.stream_index == video_stream_index) {
int len = avcodec_decode_video2(codec_ctx, frame, &got_picture, &packet);

if (len < 0) {
std::cerr << "Error decoding video frame" << std::endl;
break;
}

if (got_picture) {
y_size = frame->width * frame->height;
uv_size = y_size / 2;
fwrite(frame->data[0], 1, y_size, fp);
fwrite(frame->data[1], 1, uv_size, fp);
}
}
av_packet_unref(&packet);
}

// 刷新解码器缓冲区
packet.data = nullptr;
packet.size = 0;
res = avcodec_decode_video2(codec_ctx, frame, &got_picture, &packet);
while (res >= 0 && got_picture) {
y_size = frame->width * frame->height;
uv_size = y_size / 2;
fwrite(frame->data[0], 1, y_size, fp);
fwrite(frame->data[1], 1, uv_size, fp);
res = avcodec_decode_video2(codec_ctx, frame, &got_picture, &packet);
}

// 清理资源
fclose(fp);
av_frame_free(&frame);
avcodec_close(codec_ctx);
avformat_close_input(&format_ctx);

return 0;
}

4.3 图像处理与视觉计算

4.3.1 硬件规格

EA65xx 芯片支持专用的 SPP 硬件,可对图像进行"裁剪/缩放/补边"等视频处理操作。

硬件参数规格
  • 处理流水线:裁切 → 缩放 → 补边 → 输出格式调整(固定顺序)
  • 输入(In0)支持
    • 格式:YUV 类(NV12、I400)、RGB 类(RGB888、ARGB8888)
    • 分辨率:最小 48×48,最大 4096×2160(4K DCI)
    • 备注:RGB 输入时,输出只支持 YUV 类(固定 BT.601 公式)
  • 输出(Out0)支持
    • 格式:YUV 类(NV12、NV21、I400)
    • 分辨率:最小 48×48,最大 4096×2160(4K DCI)
  • 输出(Out1)支持
    • 格式:YUV 类(NV12、NV21、I400)、RGB 类(多种格式)
    • 分辨率:最小 48×48,最大 1920×1080(Full HD)
    • 备注:YUV 输出时支持多种 RGB2YUV 转换矩阵
  • 数据对齐要求
    • 首地址:输入输出 buffer 首地址按 4KB 对齐
    • 行跨距:行跨距按 128 字节对齐

用户可以通过 taCV 接口和 taOpenCV 接口使用 SPP 提供的功能。

4.3.2 使用 taCV

taCV 提供图像处理 SPP 硬件加速接口,可对图像进行 crop、resize 和格式转换操作。详细描述参考 API 参考的「taCV 接口详解」章节

4.3.3 使用 taOpenCV

taOpenCV 集成了硬件加速接口,以下是相关核心接口:

API接口功能描述
cv::resize()对图像进行down scale操作
cv::cvtColor()对图像进行格式转换操作
cv::imread()对jpeg图像进行解码操作
cv::imwrite()对jpeg图像进行编码操作

更多接口详见 API 参考的「taOpenCV 接口说明」章节

数据结构扩展说明

OpenCV内置标准处理的色彩空间为BGR格式,但是很多情况下,对于视频、图片源,直接在YUV色彩空间上处理,可以节省带宽和避免不必要的YUV和RGB之间的互相转换。因此taOpenCV对于Mat类进行了扩展。

  1. 在taOpenCV中,我们基于taSys提供了一个内存分配器,以便使用者保证获取连续的内存在物理地址上是连续的,内部接口也会判断Mat的数据存储内存是否连续,来决定是否调用硬件加速接口(硬件只能处理连续内存),如果没有连续内存,则调用CPU加速接口。在mat.create前,可以通过以下代码获取分配器。
mat.allocator = hal::getAllocator();
  1. 在Mat.UMatData中,引入了AVFrame成员,扩展支持各种YUV格式。其中AVFrame的格式定义与FFMPEG中的定义兼容

  2. 在Mat.UMatData中增加了addr和blk_id的定义,分别表示对应的物理内存地址和taSys的内存块ID

示例代码
#include "opencv2/opencv.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"

int main( int argc, const char** argv )
{
std::string filename = "./dog.image.jpg";
Mat image = cv::imread(filename , cv::IMREAD_COLOR_YUV);
if(image.empty())
{
printf("Cannot read image file: %s\n", filename.c_str());
return -1;
}
int out_height = 256;
int out_width = 256;
Mat img_out;
resize(image, image_out, Size(out_width,out_height));

cv::imwrite("./output.jpg", image_out);
return 0;
}

4.4 视频流输出处理

4.4.1 使用 taFFmpeg

FFmpeg 推流是指基于 FFmpeg 工具把本地产生的音视频数据流推送到流媒体服务器上。在生产端,通常会用 FFmpeg 对原始视频数据(如 RGB、YUV 等)进行压缩编码,然后封装成流媒体服务器支持的传输格式(如 RTMP、HLS 等)。

核心 API 接口
API 接口功能描述
avformat_network_init()初始化网络组件
avformat_alloc_output_context2()创建 AVFormatContext 并初始化
avformat_new_stream()为每种媒体类型创建新的输出流
avcodec_find_encoder()查找适当的编码器
avcodec_alloc_context3()为编码器创建上下文
avcodec_parameters_to_context()设置分辨率、帧率、比特率等参数
avcodec_open2()打开编码器并初始化
avcodec_parameters_from_context()从编码器上下文复制参数到流
avio_open()打开输出 URL(如 RTMP、RTSP 地址)
avformat_write_header()写入输出流的头部信息
av_frame_alloc()创建 AVFrame 结构体,用于存储原始帧数据
avcodec_send_frame()发送原始帧到编码器
avcodec_receive_packet()从编码器接收编码后的数据包
av_interleaved_write_frame()将编码后的数据包写入输出流
av_write_trailer()写入输出流的尾部信息
avcodec_free_context()释放编码器上下文
av_frame_free()释放 AVFrame
avio_closep()关闭输出
avformat_free_context()释放 AVFormatContext
示例代码
#include <iostream>
#include <unistd.h>

extern "C" {
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/imgutils.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
}

int main() {
int res;

// 1. 初始化 FFmpeg
av_register_all();
avformat_network_init();

// 2. 打开输入媒体文件并读取流头信息
const char* input_url = "/sdcard/1080.mp4";
AVFormatContext *input_format_context = NULL;
res = avformat_open_input(&input_format_context, input_url, NULL, NULL);
if (res < 0) {
std::cerr << "Failed to open input file" << std::endl;
return -1;
}

// 3. 读取数据包以获取流信息(某些流可能没有头部)
res = avformat_find_stream_info(input_format_context, NULL);
if (res < 0) {
std::cerr << "Failed to find stream info" << std::endl;
avformat_close_input(&input_format_context);
return -1;
}

// 4. 打开输出流
const char* output_url = "rtmp://[RTMP服务器地址]/[应用名]/[流名]";
AVFormatContext *output_format_context = NULL;
res = avformat_alloc_output_context2(&output_format_context, NULL, NULL, output_url);
if (res < 0 || !output_format_context) {
std::cerr << "Failed to create output context" << std::endl;
avformat_close_input(&input_format_context);
return -1;
}

if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
res = avio_open(&output_format_context->pb, output_url, AVIO_FLAG_WRITE);
if (res < 0) {
std::cerr << "Failed to open output URL" << std::endl;
avformat_free_context(output_format_context);
avformat_close_input(&input_format_context);
return -1;
}
}

// 5. 写入头部信息
res = avformat_write_header(output_format_context, NULL);
if (res < 0) {
std::cerr << "Failed to write header" << std::endl;
avio_closep(&output_format_context->pb);
avformat_free_context(output_format_context);
avformat_close_input(&input_format_context);
return -1;
}

// 6. 循环读取和写入数据包
AVPacket packet;
av_init_packet(&packet);

// 获取输入输出流信息(需要根据实际情况调整)
AVStream* input_stream = input_format_context->streams[0]; // 示例:第一个流
AVStream* output_stream = output_format_context->streams[0]; // 示例:第一个流
int output_stream_index = 0;

while (av_read_frame(input_format_context, &packet) >= 0) {
// 转换时间戳
packet.pts = av_rescale_q(packet.pts, input_stream->time_base, output_stream->time_base);
packet.dts = av_rescale_q(packet.dts, input_stream->time_base, output_stream->time_base);
packet.duration = av_rescale_q(packet.duration, input_stream->time_base, output_stream->time_base);
packet.pos = -1;
packet.stream_index = output_stream_index;

// 写入数据包(压缩码流)到输出文件
res = av_interleaved_write_frame(output_format_context, &packet);
if (res < 0) {
std::cerr << "Error writing packet" << std::endl;
break;
}
av_packet_unref(&packet);
}

// 7. 写入尾部信息
av_write_trailer(output_format_context);

// 8. 清理资源
avformat_close_input(&input_format_context);
if (!(output_format_context->oformat->flags & AVFMT_NOFILE)) {
avio_closep(&output_format_context->pb);
}
avformat_free_context(output_format_context);

return 0;
}

4.5 TA-VO

4.5.1 模块介绍

VO(Video Output)API 采用设备(Dev)、图层(Layer)、通道(Channel)、回写(Write Back)四个模块,形成完整的 VO 处理流水线:

  • 设备模块:负责管理底层物理输出硬件(如 IDS、USB 转 HDMI),进行硬件初始化和基础配置。
  • 图层模块:作为核心叠加引擎,管理独立的视频和图形显示平面,处理层级叠加、透明度合成与位置布局。
  • 通道模块:作为视频流入口,负责帧数据接收、缓冲管理和发送调度,将视频流绑定到指定图层。
  • 回写模块:实现对显示内容的捕获与回写,形成闭环。

4.5.2 使用ta-vo

核心API接口
API 接口功能描述
设备管理(ta_vo_dev)
ta_vo_dev_create(dev_id)创建 VO 设备
ta_vo_dev_get_attr(dev_ctx, &dev_attr)获取设备属性
ta_vo_dev_set_attr(dev_ctx, &dev_attr)设置设备属性
图层管理(ta_vo_layer)
ta_vo_layer_create(layer_type)创建图层(视频层/图形层)
ta_vo_layer_set_attr(layer_ctx, &layer_attr)设置图层属性
ta_vo_layer_get_attr(layer_ctx, &layer_attr)获取图层属性
ta_vo_layer_enable(layer_ctx)使能图层
ta_vo_layer_destroy(layer_ctx)销毁图层
ta_vo_layer_bind_to_dev(layer_ctx, dev_ctx)将图层绑定到设备
通道管理(ta_vo_chn)
ta_vo_chn_create(chn_id)创建通道
ta_vo_chn_set_attr(chn_ctx, &chn_attr)设置通道属性
ta_vo_chn_bind_to_layer(chn_ctx, layer_ctx)将通道绑定到图层
ta_vo_chn_send_frame(chn_ctx, frame)发送帧到通道
回写管理(ta_vo_wb)
ta_vo_wb_create(id)创建回写通道
ta_vo_wb_set_attr(wb_ctx, &wb_attr)设置回写属性
ta_vo_wb_enable(wb_ctx)使能回写功能
ta_vo_wb_bind_to_layer(wb_ctx, layer_ctx)将回写绑定到图层
ta_vo_wb_get_frame(wb_ctx)获取回写帧(捕获显示内容)
ta_vo_wb_put_frame(wb_ctx, frame)释放回写帧

接口详情见 API 参考的「ta-vo 接口说明」章节

示例代码
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include "ta_vo_common.h"
#include "ta_vo_channel.h"
#include "ta_vo_layer.h"
#include "ta_vo_wb.h"

#define WIDTH 1920
#define HEIGHT 1080
#define CH_WIDTH 640
#define CH_HEIGHT 360
#define CHN_NUM 9
#define FPS 30
#define TEST_FRAME_COUNT 60

static ta_vo_chn_ctx *chn_ctx[TA_VO_CHN_MAX];
static ta_vo_layer_ctx *video_layer_ctx = NULL;
static ta_vo_dev_ctx *dev_ctx = NULL;
static ta_vo_wb_ctx *wb_ctx = NULL;
static pthread_t thread_id[9];
static pthread_t layer_thread_id;

int ta_vo_sample(int display, int chn_num, int in_fmt, int out_fmt)
{
int ret = 0;
int frame_width = WIDTH;
int frame_height = HEIGHT;
int ch_width = CH_WIDTH;
int ch_height = CH_HEIGHT;
int fps = FPS;

ta_vo_chn_attr chn_attr[TA_VO_CHN_MAX];
ta_vo_dev_attr dev_attr;
ta_vo_wb_attr wb_attr;
ta_vo_layer_attr layer_attr;

signal(SIGINT, release_res_handler);

/* 1. 创建视频图层 */
video_layer_ctx = ta_vo_layer_create(TA_VO_LAYER_VIDEO_0);
if (!video_layer_ctx) {
TA_VO_LOG_ERROR("video layer initialization failed.");
return -1;
}

/* 2. 创建并配置通道,绑定到图层 */
for (int ch = 0; ch < chn_num; ch++) {
chn_ctx[ch] = ta_vo_chn_create(ch);
if (!chn_ctx[ch]) {
TA_VO_LOG_ERROR("chn[%d] create failed.", ch);
return -1;
}

chn_attr[ch].x = (ch % 3) * ch_width;
chn_attr[ch].y = (ch / 3) * ch_height;
chn_attr[ch].width = ch_width;
chn_attr[ch].height = ch_height;
chn_attr[ch].fps = fps;
ret = ta_vo_chn_set_attr(chn_ctx[ch], &chn_attr[ch]);
if (ret) {
TA_VO_LOG_ERROR("chn[%d] set attr failed.", ch);
return ret;
}

ret = ta_vo_chn_bind_to_layer(chn_ctx[ch], video_layer_ctx);
if (ret) {
TA_VO_LOG_ERROR("chn[%d] bind to layer failed.", ch);
return ret;
}
}

/* 3. 创建设备并绑定图层(可选,用于显示输出) */
if (display == 1) {
dev_ctx = ta_vo_dev_create(TA_VO_DEV_IDS);
if (!dev_ctx) {
TA_VO_LOG_ERROR("video dev create failed.");
return -1;
}

ta_vo_dev_get_attr(dev_ctx, &dev_attr);
dev_attr.fps = fps;
dev_attr.layer[0].format = TA_AV_PIX_FMT_NV12;
dev_attr.layer[0].on = 1;
dev_attr.layer[0].scaler_on = 1;
dev_attr.layer[0].priority = 0;
dev_attr.scaler_width = 1440;
dev_attr.scaler_height = 810;
dev_attr.scaler_x = 240;
dev_attr.scaler_y = 135;
ta_vo_dev_set_attr(dev_ctx, &dev_attr);

ret = ta_vo_layer_bind_to_dev(video_layer_ctx, dev_ctx);
if (ret) {
TA_VO_LOG_ERROR("video layer bind to dev failed.");
return ret;
}
}

/* 4. 创建回写并绑定到图层(可选,用于捕获显示内容) */
wb_ctx = ta_vo_wb_create(0);
wb_attr.src.layer = TA_VO_LAYER_VIDEO_0;
ta_vo_wb_set_attr(wb_ctx, &wb_attr);
ta_vo_wb_enable(wb_ctx);
ta_vo_wb_bind_to_layer(wb_ctx, video_layer_ctx);

/* 5. 设置图层属性 */
layer_attr.format = TA_AV_PIX_FMT_NV12;
layer_attr.use_av_frame = 1;
layer_attr.hw_layer_id = 0;
layer_attr.queue_size = MAX_QUEUES;
layer_attr.width = frame_width;
layer_attr.height = frame_height;
layer_attr.fps = fps;
ta_vo_layer_set_attr(video_layer_ctx, &layer_attr);

/* 6. 初始化帧数据 */
for (int i = 0; i < TEST_FRAME_COUNT; i++) {
ret = frame_init(i, frame_width, frame_height, in_fmt);
if (ret) {
TA_VO_LOG_ERROR("frame[%d] init failed.", i);
goto clean;
}

ret = load_test_data(frame[i]->av_frame->data[0], i,
frame_width, frame_height, in_fmt);
if (ret) {
TA_VO_LOG_ERROR("load frame[%d] data failed.", i);
goto clean;
}
}

/* 7. 使能图层 */
ta_vo_layer_enable(video_layer_ctx);

/* 8. 启动发送线程 */
for (int i = 0; i < chn_num; i++) {
pthread_create(&thread_id[0], NULL, video_frame_send_thread,
(void *)chn_ctx[i]);
}

/* 9. 启动回写捕获线程 */
pthread_create(&layer_thread_id, NULL, wb_thread_func, (void *)wb_ctx);

/* 10. 主线程等待 */
while (1)
sleep(1);

clean:
release_res_handler(0);
return 0;
}

五、综合案例与最佳实践

5.1 章节前言

本章节旨在通过一个从视频输入到 AI 结果输出的完整案例,将前序章节的理论知识与实际代码相结合,帮助开发者深入理解 TACO SDK 的核心工作流和设计理念。

我们将以一个实时的目标检测与追踪应用(mot)为例,逐一解析其关键实现,并在此过程中提炼出能够最大化硬件性能、提升开发效率的"最佳实践"。

5.2 核心开发理念回顾

在深入案例代码之前,我们重申贯穿整个 TACO SDK 设计的几个核心理念:

内存为王(Memory First)

TACO 的性能基石是其高效的内存管理机制。所有需要被硬件模块(VDECSPPNPUVENC)访问的数据,都必须存放在由 Dmabufheap 管理的媒体域内存中。这是实现 零拷贝 高性能数据通路的前提。

拥抱硬件加速(Hardware Acceleration)

应用开发中应最大限度地利用芯片提供的硬件加速能力,包括:

  • 使用 h264_taco/hevc_taco 进行视频解码
  • 使用 taCV 接口进行图像处理(如 Resize)
  • 使用 taRuntime 执行 NPU 推理

将 CPU 从繁重的计算任务中解放出来,专注于高层级的业务逻辑。

物理地址优先(Physical Address Priority)

在硬件模块之间流转数据时,直接传递物理地址是最高效的方式:

  • 避免操作系统层面的虚拟地址到物理地址的多次转换
  • 避免不必要的数据拷贝
  • 如案例所示,从解码后的帧中获取物理地址,并将其一路传递给 taCVtaRuntime,是性能优化的关键

5.3 案例解析:实时视频目标检测与推流(mot)

本案例完整地实现了从"拉流 → 解码 → AI 处理 → 编码 → 推流"的全流程,是 TACO SDK 各项能力的一个综合性展示。

获取代码方式参考 「TACO 应用开发入门」文档的「Hello, TACO:运行第一个 AI 应用」章节

5.3.1 业务流程图

该案例程序包含两条核心线程:

Pipeline 线程(生产者)

负责从视频源(文件或 RTSP 流)获取数据,依次进行硬件解码、硬件缩放、NPU 推理、CPU 后处理与 OSD 绘制,最后将处理好的帧放入一个全局队列。

// Pipeline Thread(生产者)
[视频输入] → [taFFmpeg 硬件解码] → [taCV 硬件 Resize] → [taRuntime NPU 推理] → [CPU 后处理/绘制] → [全局队列]
Encoder 线程(消费者)

从全局队列中取出处理好的帧,使用硬件进行 JPEG 编码,并通过 taFFmpeg 封装成 MJPEG 格式的 RTSP 流发布出去。

// Encoder Thread(消费者)
[全局队列] → [硬件 JPEG 编码] → [taFFmpeg RTSP 推流]

5.3.2 关键步骤与代码实现

5.3.2.1 核心:实现零拷贝的内存管理(FramePacket)

为了实现高效的数据流转,案例设计了 FramePacket 类来封装一个视频帧及其对应的 Dmabufheap 内存信息。这是实现零拷贝的关键。

最佳实践:利用 TACO SDK 对 FFmpeg 的扩展能力,在调用 av_frame_get_buffer 时,让 taFFmpeg 自动从 Dmabufheap 的公共缓存池中申请内存。然后,通过查询 AVFrame 的元数据(metadata)来获取该内存块的 ID(pool_blk_id),进而查询到其物理地址。

代码解析ffmpeg_decoder.cpp):


static uint32_t get_blk_id(AVFrame* frame) {
// 关键步骤2: 从 AVFrame 的元数据中获取 taSys 内存块 ID
AVDictionaryEntry* tag = av_dict_get(frame->metadata, "pool_blk_id", nullptr, 0);
if (!tag) return 0;
return (uint32_t)strtoul(tag->value, nullptr, 10);
}

AVFrame* alloc_nv12(int w, int h) {
AVFrame* f = av_frame_alloc();
// ...
f->format = AV_PIX_FMT_NV12;
f->width = w;
f->height = h;

// 关键步骤1: taFFmpeg 自动从 taSys 内存池分配 buffer
int ret = av_frame_get_buffer(f, 0);

return f;

}

通过这种方式,一块物理内存在分配后:

  • 其虚拟地址被 CPU(taFFmpeg、OpenCV)使用
  • 其物理地址被硬件模块(taCVtaRuntime)使用
  • 全程无需数据拷贝
5.3.2.2 硬件加速视频解码(ffmpeg_decoder.cpp)

最佳实践:在打开解码器时,通过 avcodec_find_decoder_by_name 明确指定使用 TACO 提供的硬件解码器。

代码解析FFmpegDecoder::open):

// 根据视频流的编码格式,选择对应的硬件解码器
if (video_stream->codecpar->codec_id == AV_CODEC_ID_H264) {
codec = avcodec_find_decoder_by_name("h264_taco");
}
if (video_stream->codecpar->codec_id == AV_CODEC_ID_HEVC) {
codec = avcodec_find_decoder_by_name("hevc_taco");
}
// ...
// 使用 avcodec_send_packet / avcodec_receive_frame 循环解码
// 解码输出的 AVFrame* frame 的数据区已位于 Dmabufheap 管理的内存中
5.3.2.3 硬件加速图像预处理(ffmpeg_decoder.cpp)

最佳实践:将解码后的 AVFrame 封装为 ta_image_t 结构体,调用 ta_cv_image_convert_padding 接口,利用硬件加速完成图像缩放,以满足 NPU 模型输入尺寸要求。

代码解析FFmpegDecoder::nv12_from_frame):

bool FFmpegDecoder::nv12_from_frame(AVFrame* frame, FramePacket& packet) {
// 分配 NPU 输入帧(网络输入尺寸,taco 物理内存)
AVFrame* npu = alloc_nv12(cfg_.input_net_w, cfg_.input_net_h);
if (!npu) {
std::cerr << "[FFmpegDecoder] alloc npu frame failed\n";
return false;
}
npu->pts = frame->pts;

uint32_t blk_id_in = get_blk_id(frame);
uint32_t blk_id_out = get_blk_id(npu);
if (!blk_id_in || !blk_id_out) {
av_frame_free(&npu);
std::cerr << "[FFmpegDecoder] missing pool_blk_id\n";
return false;
}

// tacv 硬件 resize:原始分辨率 NV12 -> 网络输入尺寸 NV12
ta_image_t image_in, image_out;
ta_cv_image_create_ext(height_, width_,
FORMAT_NV12, &image_in, blk_id_in);
ta_cv_image_create_ext(cfg_.input_net_h, cfg_.input_net_w,
FORMAT_NV12, &image_out, blk_id_out);
memset(image_out.frame.data[0],0,image_out.width*image_out.height);
memset(image_out.frame.data[0]+image_out.width*image_out.height,128,image_out.width*image_out.height/2);
ta_cv_padding_attr_t padding_attr;
build_center_letterbox_attr(width_,height_,cfg_.input_net_w,cfg_.input_net_h,&padding_attr);
ta_cv_rect_t rect_crop;
memset(&rect_crop, 0, sizeof(rect_crop));
rect_crop.start_x = 0;
rect_crop.start_y = 0;
rect_crop.crop_w = width_;
rect_crop.crop_h = height_;

int ret = ta_cv_image_convert_padding(image_in,image_out,rect_crop,padding_attr,TA_CV_INTER_BILINEAR);
ta_cv_image_destroy_ext(&image_in);
ta_cv_image_destroy_ext(&image_out);

return true;
}
5.3.2.4 NPU 推理(yolo11_detector.cpp)

最佳实践:使用 ta_runtime_set_input_pha 接口,直接向 NPU 提交预处理后图像的物理地址。这是最高效的输入方式,避免了任何从系统内存到 NN 域内存的拷贝或映射开销。

代码解析YOLO11Detector::preprocess):

#ifdef INFER_INPUT_BLK_PHY_ADDR
// 从 FramePacket 对象中获取预处理后图像的物理地址
unsigned long long phyAddr = frame.npu_phy_addr;

taconn_input_phy_t input[2];
// 设置 Y 分量的物理地址和大小
input[0].physical_table[0] = phyaddr;
input[0].size_table[0] = (long long unsigned)net_w * net_h;
// 设置 UV 分量的物理地址和大小
phy_input[1].physical_table[0] = frame.npu_phy_addr + (long long unsigned)net_w * net_h;
phy_input[1].size_table[0] = (long long unsigned)net_w * net_h / 2;

// 设置输入并运行推理
ret = ta_runtime_set_input_pha(&runtime_context_, input_num_, phy_input);
if (ret != 0) {
/* 错误处理 */
}

ret = ta_runtime_run_network(&m_nnrt_context);
if (ret != 0) {
/* 错误处理 */
}
#endif
5.3.2.5 CPU 后处理与结果绘制

最佳实践:根据 NPU 推理给出的结果,使用 CPU 进行后处理,并最终获得检测目标。

代码分析YOLO11Detector::decode_outputs & Reporter::draw_tracks):

// 后处理,可以参考该函数,对yolov11模型输出做了一系列后处理操作
YOLO11Detector::decode_outputs(const std::vector<taconn_buffer_t>& outputs,
const LetterboxMeta& meta,
std::vector<taconn_inout_attr_t>& attrs,
std::vector<Detection>& detections);
// ...

// generate_proposals:从单个输出层解析候选框,输出 Object 列表
generate_proposals(STRIDES[i], outputs[i].data, data_format,
zp, scale, conf_thresh_, proposals, lbox_w, lbox_h);
// 排序过滤框
qsort_descent_inplace(proposals);
std::vector<int> picked;
nms_sorted_bboxes(proposals, picked, nms_thresh_);
// ...
// 对坐标进行缩放和边界处理

// 更新检测目标的最终坐标
float x1 = obj.box.left;
float y1 = obj.box.top;
float x2 = obj.box.left + obj.box.width;
float y2 = obj.box.top + obj.box.height;
meta.restore_coords(x1, y1, x2, y2);

// 结果绘制
// ...
draw_tracks(FramePacket& packet)
// ...

5.4 通用最佳实践总结

1. 优先使用 Dmabufheap 内存

任何需要在硬件单元间流转的数据(视频帧、模型输入输出),都应通过以下方式分配:

  • 使用Dmabufheap系列接口来申请内存与获取内存物理地址。接口详细使用可参考 libdmabufheap 接口详解
  • SDK 封装后的 av_frame_get_buffer

2. 理解数据流

始终清晰地了解每一块内存的生产者和消费者是谁(CPU 还是硬件):

  • 生产者线程:数据流有序地进入硬件解码模块、硬件缩放、NPU 推理、CPU 后处理与 OSD 绘制,最后将处理好的帧放入一个全局队列
  • 消费者线程:数据从全局队列中提取并进行硬件编码,再发布出来

3. 利用异步处理

mot 中的生产者-消费者模型是一个优秀的实践:

  • 将耗时较长的解码、推理与编码、推流解耦
  • 形成流畅的并行处理管道
  • 有效提升系统吞吐率

六、API 参考

6.1 libdmabufheap 接口详解

本节覆盖内存管理相关 API,按功能分组说明,并在每组下给出 C++/C 对应接口。

6.1.1 分配器生命周期管理

以下接口来自 include/BufferAllocator/BufferAllocatorWrapper.h,用于 C 侧生命周期管理。 这些接口仅在 C API 提供,C++ API 无一一对应项,原因如下:

  • CreateDmabufHeapBufferAllocator / FreeDmabufHeapBufferAllocator:C++ 通过 BufferAllocator 对象构造与析构管理生命周期,不需要显式创建/释放函数。
  • GetStaticAllocator / ReleaseStaticAllocator:这是 C 封装层为兼容 C 调用方式提供的进程级静态实例访问接口;C++ 侧可直接在调用方管理对象或使用静态对象模式。
6.1.1.1 CreateDmabufHeapBufferAllocator

描述

创建分配器实例。

语法

BufferAllocator* CreateDmabufHeapBufferAllocator();

返回值

返回值描述
NULL成功,返回分配器 BufferAllocator 句柄
NULL失败
6.1.1.2 FreeDmabufHeapBufferAllocator

描述

释放通过 CreateDmabufHeapBufferAllocator 创建的实例。

语法

void FreeDmabufHeapBufferAllocator(BufferAllocator* buffer_allocator);

参数说明

参数名称描述输入/输出
buffer_allocator分配器 BufferAllocator 句柄(可为 NULL输入
6.1.1.3 GetStaticAllocator

描述

获取进程级静态分配器实例。

语法

BufferAllocator* GetStaticAllocator();

返回值

返回值描述
NULL返回分配器 BufferAllocator 句柄实例

注意事项

  • 静态实例在进程生命周期内有效,调用方不应释放。
6.1.1.4 ReleaseStaticAllocator

描述

静态分配器释放占位接口(当前实现为 no-op)。

语法

void ReleaseStaticAllocator(BufferAllocator* buffer_allocator);

参数说明

参数名称描述输入/输出
buffer_allocator分配器 BufferAllocator 句柄指针输入

6.1.2 缓冲区分配

6.1.2.1 C++:BufferAllocator::Alloc

描述

从指定 DMA-BUF heap 分配缓冲区。

语法

int Alloc(const std::string& heap_name, size_t len);

参数说明

参数名称描述输入/输出
heap_nameheap 名称,如 carveout-heaplinux,cmasystem输入
len申请大小(字节)输入

返回值

返回值描述
>= 0成功,返回 dmabuf fd
< 0失败,返回错误码

注意事项

  • 返回的 fd 由调用方负责 close()
  • heap_name 需要是系统已存在的 /dev/dma_heap/* 设备名。
6.1.2.2 C:DmabufHeapAlloc

描述

从指定 heap 分配 DMA-BUF。

语法

int DmabufHeapAlloc(BufferAllocator* buffer_allocator, const char* heap_name, size_t len);

参数说明

参数名称描述输入/输出
buffer_allocator分配器 BufferAllocator 句柄,不能为 NULL输入
heap_nameheap 名称输入
len申请大小(字节)输入

返回值

返回值描述
>= 0成功,返回 dmabuf fd
< 0失败,返回错误值

6.1.3 缓冲区元信息与调试

6.1.3.1 C++:BufferAllocator::GetPhysAddr

描述

查询 DMA-BUF 的物理地址及物理连续长度。

语法

int GetPhysAddr(unsigned int dmabuf_fd, uint64_t* addr, uint64_t* len);

参数说明

参数名称描述输入/输出
dmabuf_fd目标缓冲区 dmabuf fd输入
addr输出物理地址输出
len输出物理连续长度输出

返回值

返回值描述
0成功
< 0失败,返回负错误码

注意事项

  • 仅在底层 heap 与内核支持物理地址查询时有效。
  • addrlen 必须为有效指针。
6.1.3.2 C:DmabufHeapGetPhysAddr

描述

获取 DMA-BUF 物理地址与物理连续长度。

语法

int DmabufHeapGetPhysAddr(BufferAllocator* buffer_allocator, unsigned int dmabuf_fd,
uint64_t* addr, uint64_t* len);

参数说明

参数名称描述输入/输出
buffer_allocator分配器 BufferAllocator 句柄,不能为 NULL输入
dmabuf_fd目标缓冲区 dmabuf fd输入
addr输出物理地址输出
len输出物理连续长度输出

返回值

返回值描述
0成功
< 0失败,返回负错误码
6.1.3.3 C++:BufferAllocator::DmabufSetName

描述

设置 DMA-BUF 调试名称。

语法

static int DmabufSetName(unsigned int dmabuf_fd, const std::string& name);

参数说明

参数名称描述输入/输出
dmabuf_fd目标缓冲区 dmabuf fd输入
name调试名称字符串输入

返回值

返回值描述
0成功
-1失败,errno 指示原因
6.1.3.4 C:DmabufSetName

描述

设置 DMA-BUF 调试名称。

语法

int DmabufSetName(BufferAllocator* buffer_allocator, unsigned int dmabuf_fd, const char* name);

参数说明

参数名称描述输入/输出
buffer_allocator分配器 BufferAllocator 句柄,不能为 NULL输入
dmabuf_fd目标缓冲区 dmabuf fd输入
name调试名称输入

返回值

返回值描述
0成功
-1失败,errno 指示原因
6.1.3.5 C++:BufferAllocator::GetDmabufHeapList

描述

获取系统可用的 DMA-BUF heap 名称列表。

语法

static std::unordered_set<std::string> GetDmabufHeapList();

返回值

返回值描述
std::unordered_set<std::string>可用 heap 名称集合

6.1.4 类型与句柄说明

dmabuf fdint
  • 本库返回的 fd 是 Linux 文件描述符(File Descriptor),代表一个 DMA-BUF 内核对象引用。
  • fd 在“创建它的进程”内直接有效;跨进程使用时,需要通过 FD 传递机制(如 Unix Domain Socket + SCM_RIGHTS)发送给目标进程。
  • fd 不是虚拟地址;CPU 访问内存需先执行 mmap,并在完成后 munmap
  • 每次成功分配得到的 fd,都应在不再使用时调用 close(fd),否则会造成句柄泄漏。
  • 一个 fd 可被复制(dup/dup2),每个副本都需要独立 close 才会真正释放引用。
BufferAllocator*
  • 在 C 接口中,BufferAllocator* 是不透明句柄(opaque handle),外部不应访问其内部结构。
  • 动态实例使用方式:CreateDmabufHeapBufferAllocator 创建,FreeDmabufHeapBufferAllocator 释放。
  • 静态实例使用方式:GetStaticAllocator 获取进程级单例;ReleaseStaticAllocator 当前实现为 no-op。

6.1.5 libdmabufheap 示例程序

// C++ usage example (Alloc + SetName + mmap + GetPhysAddr)
#include <BufferAllocator/BufferAllocator.h>

#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>

int main() {
BufferAllocator allocator;

const size_t size = 4096;
int fd = allocator.Alloc("carveout-heap", size); // or "system", "linux,cma"
if (fd < 0) return -1;

(void)BufferAllocator::DmabufSetName((unsigned int)fd, "demo_cpp_dmabuf");

void* vaddr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr != MAP_FAILED) {
((volatile uint8_t*)vaddr)[0] = 0x5A;
munmap(vaddr, size);
}

uint64_t phys = 0, phys_len = 0;
(void)allocator.GetPhysAddr((unsigned int)fd, &phys, &phys_len);

close(fd);
return 0;
}

/* C usage example (Create + Alloc + SetName + mmap + GetPhysAddr + close + Free) */
#include <BufferAllocator/BufferAllocatorWrapper.h>

#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>

int main(void) {
BufferAllocator* allocator = CreateDmabufHeapBufferAllocator();
if (!allocator) return -1;

size_t size = 4096;
int fd = DmabufHeapAlloc(allocator, "carveout-heap", size);
if (fd < 0) {
FreeDmabufHeapBufferAllocator(allocator);
return -1;
}

(void)DmabufSetName(allocator, (unsigned int)fd, "demo_c_dmabuf");

void* vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (vaddr != MAP_FAILED) {
((volatile uint8_t*)vaddr)[0] = 0x5A;
munmap(vaddr, size);
}

uint64_t phys = 0, phys_len = 0;
(void)DmabufHeapGetPhysAddr(allocator, (unsigned int)fd, &phys, &phys_len);

close(fd);
FreeDmabufHeapBufferAllocator(allocator);
return 0;
}

6.2 taCV 接口详解

模块提供的所有接口都是同步接口,用户在调用接口时需要同时提供输入输出 buffer,如果接口返回成功,则输出 buffer 中已含有输出图像。接口依赖 dmabufheap 模块提供帧缓存,用户在创建公共缓存池时,应为本模块预留合适大小和数量的帧缓存。taCV 提供图像处理 SPP 硬件加速接口,可以对图像做 crop、resize 和格式转换的操作。

6.2.1 ta_cv_image_create_ext()

描述

创建并填充一个 ta_image_t 结构体。建议使用该接口创建ta_image_t结构体。

语法

tacv_status_t ta_cv_image_create_ext(
int img_h,
int img_w,
ta_image_format_ext_t image_format,
ta_image_t* p_image,
unsigned int blk_id
);

参数说明

参数名称描述输入/输出
img_h图像高度输入
img_w图像宽度输入
image_format图像格式输入
data_type图像的数据格式输入
p_image指向 ta_image_t 结构体的指针输出
blk_id从 dmabuffer 中申请的内存描述符输入

返回值

返回值描述
0成功
非 0失败

注意事项

  • 强烈建议用户通过专用 API 来创建/销毁 ta_image_t 结构体
  • 创建和销毁接口必须成对使用

6.2.2 ta_cv_image_destroy_ext()

描述

销毁一个 ta_image_t 结构体。

语法

tacv_status_t ta_cv_image_destroy_ext(
ta_image_t *p_image
);

参数说明

参数名称描述输入/输出
p_image指向 ta_image_t 结构体的指针输入

返回值

返回值描述
0成功
非 0失败

注意事项

  • 强烈建议用户通过专用 API 来创建/销毁 ta_image_t 结构体
  • 创建和销毁接口必须成对使用
  • 如果 p_image 引用的帧存是 SDK 申请的,则会在此接口内回收;如果是用户自己申请的,则需要用户自己负责回收

6.2.3 ta_cv_image_create()

描述

通过ta_avframe_t结构体创建并填充一个 ta_image_t 结构体。推荐使用ta_cv_image_create_ext()。

语法

tacv_status_t ta_cv_image_create(
int img_h,
int img_w,
ta_image_format_t image_format,
ta_data_type_t data_type,
ta_image_t *p_image,
ta_avframe_t* frame
);

参数说明

参数名称描述输入/输出
img_h图像高度,单位是行输入
img_w图像宽度,单位是像素输入
image_format图像格式 ta_image_format_t输入
data_type图像的数据格式输入
p_image指向 ta_image_t 结构体的指针输出
frameta_avframe_t 结构体指针(AVFrame)输出

返回值

返回值描述
0成功
非 0失败

注意事项

  • 强烈建议用户通过专用 API 来创建/销毁 ta_image_t 结构体
  • 创建和销毁接口必须成对使用

6.2.4 ta_cv_image_destroy()

描述

销毁一个 ta_image_t 结构体。

语法

tacv_status_t ta_cv_image_destroy(
ta_image_t *p_image
);

参数说明

参数名称描述输入/输出
p_image指向 ta_image_t 结构体的指针输出

返回值

返回值描述
0成功
非 0失败

注意事项

  • 强烈建议用户通过专用 API 来创建/销毁 ta_image_t 结构体
  • 创建和销毁接口必须成对使用
  • 如果 p_image 引用的帧存是 SDK 申请的,则会在此接口内回收;如果是用户自己申请的,则需要用户自己负责回收

6.2.5 ta_cv_image_resize

描述

对输入图像进行缩放处理,当前仅支持图像下采样(downscale),不支持上采样(upscale)。

语法

tacv_status_t ta_cv_image_resize(
ta_cv_resize_image_t* resize_attr,
ta_image_t input,
ta_image_t output);

参数说明

参数名称描述输入/输出
resize_attrta_cv_resize_image_t指针,保存resize信息输入
input输入图像信息输入
output输出图像信息输出

返回值

返回值描述
0成功
非 0失败

格式支持

Input_Image_FormatOutput_Image_Format
FORMAT_NV12FORMAT_NV12

注意事项

  • 最大缩放比为 128,最大输入输出分辨率为 4096×2160
  • 只支持缩小
  • crop_width >= resize_width
  • 宽/高需为 16 的倍数

6.2.6 ta_cv_image_crop

描述

对输入图像执行裁剪操作。根据指定的裁剪区域,从输入图像中裁剪出一个或多个目标图像。

语法

tacv_status_t ta_cv_image_crop(
int crop_num,
ta_cv_rect_t* rects,
ta_image_t input,
ta_image_t* output);

参数说明

参数名称描述输入/输出
crop_num需要 crop 的数量输入
rectsta_cv_rect_t指针,保存裁剪区域信息输入
input输入图像信息输入
output输出图像信息指针输出

返回值

返回值描述
0成功
非 0失败

格式支持

Input_Image_FormatOutput_Image_Format
FORMAT_NV12FORMAT_NV12

注意事项

  • 输入图像与输出图像的最大分辨率为 4096 × 2016
  • 裁剪区域的宽度 crop_width 和高度 crop_height 必须为偶数。
  • 裁剪区域必须位于输入图像有效范围内,即: start_x + crop_width <= input_width start_y + crop_height <= input_height
  • 输出图像缓冲区大小 size 必须为 16 的整数倍。

6.2.7 ta_cv_image_csc_convert_to

描述

对输入图像进行预处理,支持裁剪(crop)、缩放(resize)和颜色空间转换(CSC)操作,可单独或组合使用,并将处理结果输出到目标图像。

语法

tacv_status_t ta_cv_image_csc_convert_to(
ta_image_t input,
ta_image_t output,
ta_cv_rect_t crop_rect,
ta_cv_resize_image_t* resize,
csc_type_t csc_typ);

参数说明

参数名称描述输入/输出
input输入图像信息输入
output输出图像信息输出
crop_rectta_cv_rect_t结构体,保存裁剪区域信息输入
resizeta_cv_resize_image_t指针,保存resize信息输入
csc_typcsc_type_t颜色空间转换类型输入

返回值

返回值描述
0成功
非 0失败

格式支持

Input_Image_FormatOutput_Image_Format
FORMAT_NV12FORMAT_NV12
FORMAT_NV12FORMAT_NV21
FORMAT_NV12FORMAT_RGB_PACKED
FORMAT_NV12FORMAT_BGR_PACKED
FORMAT_NV12FORMAT_RGB_PLANAR
FORMAT_NV12FORMAT_BGR_PLANAR
FORMAT_NV12FORMAT_ABGR_PACKED
FORMAT_NV12FORMAT_ARGB_PACKED

注意事项

  • 最大缩放比为 128,最大输入输出分辨率为 4096×2160
  • 只支持缩小
  • crop_width >= resize_width
  • 宽/高需为 16 的倍数

6.2.8 ta_cv_image_jpeg_enc

描述

实现对图像进行 JPEG 编码操作。

语法

tacv_status_t ta_cv_image_jpeg_enc(
ta_image_t* src,
unsigned int jpeg_data_blk,
size_t* out_size,
int quality_factor);

参数说明

参数名称描述输入/输出
src输入图像指针输入
jpeg_data_blk输出 buffer 的 blk_id输入
out_size输出 buffer 的 size 指针输入/输出
quality_factor图像质量因子输入

返回值

返回值描述
0成功
非 0失败

格式支持

Input_Image_Format
FORMAT_NV12
FORMAT_YUV420P

注意事项

  • 申请输出 buffer 的大小要大于等于输入 buffer 的大小
  • 支持大小 96×328192×8192(宽×高)
  • widthheight 必须为偶数
  • 图像质量因子 quality_factor 的取值范围为 (0, 100]

6.2.9 ta_cv_image_jpeg_dec

描述

实现对 JPEG 图像进行解码操作。

语法

tacv_status_t ta_cv_image_jpeg_dec(
size_t in_size,
unsigned int jpeg_in_blk_id,
ta_image_t *dst);

参数说明

参数名称描述输入/输出
in_size输入图像 buffer 大小输入
jpeg_in_blk_id输入图像 block_id输入
dst输出图像信息指针输入/输出

返回值

返回值描述
0成功
非 0失败

格式支持

Output_Image_Format
FORMAT_NV12
FORMAT_NV21
FORMAT_RGB_PACKED
FORMAT_BGR_PACKED
FORMAT_BGR_PLANAR
FORMAT_RGB_PLANAR

注意事项

  • 最大输入输出分辨率 32768×32768
  • 宽/高需为 16 的倍数
  • 调用接口前需要创建输出图像
  • 调用接口前需要准备好输入输出 buffer

6.2.10 ta_cv_image_convert_padding

描述

实现对图像进行裁剪(crop)、缩放(resize)、颜色空间转换(CSC)和填充(padding)操作,可单独或组合使用。

语法

tacv_status_t ta_cv_image_convert_padding(
ta_image_t input,
ta_image_t output,
ta_cv_rect_t crop_rect,
ta_cv_padding_attr_t padding_attr,
ta_cv_resize_algorithm_t algorithm
);

参数说明

参数名称描述输入/输出
input输入图像输入
output输出图像输出
crop_rectta_cv_rect_t结构体保存输入图像的裁剪信息输入
padding_attrta_cv_padding_attr_t结构体输出图像位置信息输入
algorithmta_cv_resize_algorithm_t枚举保存缩放算法类型输入

返回值

返回值描述
0成功
非 0失败

格式支持

Input_Image_FormatOutput_Image_Format
FORMAT_NV12FORMAT_NV12
FORMAT_NV12
FORMAT_BGR_PACKED
FORMAT_RGB_PACKED
FORMAT_BGR_PLANAR
FORMAT_RGB_PLANAR
FORMAT_RGBA_PACKED
FORMAT_BGRA_PACKED

注意事项

  • 输出为 NV12 格式最大分辨率为 4096×2160
  • 输出 RGB 系列格式最大分辨率为 1920×1080

6.2.11 ta_cv_image_stitch

描述

实现图像拼接的效果,支持裁剪(crop)、缩放(resize)、颜色空间转换(CSC)和填充(padding)操作,可单独或组合使用,可将两张或多张图像拼接到一张图像并输出。

语法

tacv_status_t ta_cv_image_stitch(
int input_num,
ta_image_t* input,
ta_image_t output,
ta_cv_rect_t* dst_crop_rect,
ta_cv_rect_t* src_crop_rect,
ta_cv_resize_algorithm_t algorithm
);

参数说明

参数名称描述输入/输出
input_num输入图像数量输入
input输入图像指针输入
output输出图像输出
dst_crop_rectta_cv_rect_t结构体保存输出图像中小图的坐标和宽高信息输入
src_crop_rectta_cv_rect_t结构体目标小图的坐标和宽高信息输入
algorithmta_cv_resize_algorithm_t枚举保存缩放算法类型输入

返回值

返回值描述
0成功
非 0失败

格式支持

Input_Image_FormatOutput_Image_Format
FORMAT_NV12FORMAT_NV12
FORMAT_NV12
FORMAT_BGR_PACKED
FORMAT_RGB_PACKED
FORMAT_BGR_PLANAR
FORMAT_RGB_PLANAR
FORMAT_RGBA_PACKED
FORMAT_BGRA_PACKED

注意事项

  • 输出为 NV12 格式最大分辨率为 4096×2160
  • 输出 RGB 系列格式最大分辨率为 1920×1080

6.2.12 ta_cv_copy_to

描述

对输入图像做拷贝操作,把输入图像拷贝到输出图像的指定位置。

语法

tacv_status_t ta_cv_image_copy_to(
ta_image_t input,
ta_image_t output,
ta_cv_copy_to_t copy_to_attr
);

参数说明

参数名称描述输入/输出
input输入图像输入
output输出图像输出
copy_to_attrta_cv_copy_to_t结构体保存copy 图像位置信息输入

返回值

返回值描述
0成功
非 0失败

格式支持

NumInput_Image_FormatOutput_Image_Format
1FORMAT_NV12FORMAT_NV12

注意事项

  • 输入图片分辨率必须小于输出图片分辨率

6.2.13 taCV 结构体说明

关于图像帧
ta_image_t

语法

typedef struct ta_image_s {
int width;
int height;
int plane_num;
ta_image_format_ext_t image_format;
ta_image_data_format_ext_t data_type;
ta_image_private_t * image_private;
ta_image_frame_t frame;
} ta_image_t;

参数说明

参数名称描述备注
widthimage 宽
heightimage 高
plane_numimage 平面数
image_formatimage 格式
data_typeimage 数据类型在 tacv 中,单通道单个像素都为 8bit(即 1N_BYTE)
image_privateimage 私有数据保留参数,暂时没有使用
frame帧结构体描述图像 buffer 信息

ta_image_frame_t

语法

typedef struct ta_image_frame_s {
uint8_t *data[8];
int width;
int height;
unsigned int blk_id;
uint64_t phy_addr;
int size[4];
int format;
uint64_t phy_len;
} ta_image_frame_t;

参数说明

参数名称描述备注
data各平面的虚拟地址
width图像宽度
height图像高度
blk_iddmabuf 描述符
phy_addr图片内存物理地址
size各平面占字节数
format图片格式
phy_len图像内存实际物理地址长度

ta_image_format_ext_t

语法

typedef enum ta_image_format_ext_e {
FORMAT_YUV420P,
FORMAT_YUV422P,
FORMAT_YUV444P,
FORMAT_NV12,
FORMAT_NV21,
FORMAT_NV16,
FORMAT_NV61,
FORMAT_NV24,
FORMAT_RGB_PLANAR,
FORMAT_BGR_PLANAR,
FORMAT_RGB_PACKED,
FORMAT_BGR_PACKED,
FORMAT_RGBP_SEPARATE,
FORMAT_BGRP_SEPARATE,
FORMAT_GRAY,
FORMAT_HSV_PLANAR,
FORMAT_ARGB_PACKED,
FORMAT_ABGR_PACKED,
FORMAT_YUV444_PACKED,
FORMAT_YVU444_PACKED,
FORMAT_YUV422_YUYV,
FORMAT_YUV422_YVYU,
FORMAT_YUV422_UYVY,
FORMAT_YUV422_VYUY,
FORMAT_RGBYP_PLANAR,
FORMAT_HSV180_PACKED,
FORMAT_HSV256_PACKED,
FORMAT_BAYER,
} ta_image_format_ext_t;

参数说明

枚举值描述
FORMAT_YUV420P三平面 YUV420 格式图片
FORMAT_YUV422P三平面 YUV422 格式图片
FORMAT_YUV444P三平面 YUV444 格式图片
FORMAT_NV12两平面 NV12 格式图片,Y 单独一个平面,UV 交错排列在一个平面
FORMAT_NV21两平面 NV21 格式图片,Y 单独一个平面,VU 交错排列在一个平面
FORMAT_NV16两平面 NV16 格式图片,Y 单独一个平面,VU 交错排列在一个平面
FORMAT_NV61两平面 NV61 格式图片,Y 单独一个平面,VU 交错排列在一个平面
FORMAT_NV24两平面 NV24 格式图片,Y 单独一个平面,UV 交错排列在一个平面
FORMAT_RGB_PLANAR单平面 RGB 格式图片,RGB 分开排列(RRR....GGG...BBB)
FORMAT_BGR_PLANAR单平面 BGR 格式图片,BGR 分开排列(BBB....GGG...RRR)
FORMAT_RGB_PACKED单平面 RGB 格式图片,RGB 交错排列(RGBRGB...RGB)
FORMAT_BGR_PACKED单平面 BGR 格式图片,BGR 交错排列(BGRBGR...BGR)
FORMAT_RGBP_SEPARATE三平面 RGB 格式图片,RGB 分开排列各占一个平面
FORMAT_BGRP_SEPARATE三平面 BGR 格式图片,BGR 分开排列各占一个平面
FORMAT_GRAY单平面灰度图格式的图片
FORMAT_HSV_PLANAR三平面 HSV 格式图片,H 范围 0~180
FORMAT_ARGB_PACKED单平面 ARGB 格式图片,ARGB 交错排列(ARGBARGB....ARGB)
FORMAT_ABGR_PACKED单平面 ABGR 格式图片,ABGR 交错排列(ABGRABGR...ABGR)
FORMAT_YUV444_PACKED单平面 YUV444 格式图片,YUV 交错排列(YUVYUV...YUV)
FORMAT_YVU444_PACKED单平面 YVU444 格式图片,YVU 交错排列(YVUYVU...YVU)
FORMAT_YUV422_YUYV单平面 YUV422 格式图片,YUYV 交错排列
FORMAT_YUV422_YVYU单平面 YUV422 格式图片,YVYU 交错排列
FORMAT_YUV422_UYVY单平面 YUV422 格式图片,UYVY 交错排列
FORMAT_YUV422_VYUY单平面 YUV422 格式图片,VYUY 交错排列
FORMAT_RGBYP_PLANAR四平面 RGBY 格式图片
FORMAT_HSV180_PACKED单平面的 HSV 格式,HSV 交错排列,H 范围 0~180
FORMAT_HSV256_PACKED单平面的 HSV 格式,HSV 交错排列,H 范围 0~255
FORMAT_BAYER单平面 bayer 格式图片,排列方式:RGGBRGGB...RGGB。宽高为偶数

关于图像处理
ta_cv_resize_image_t

语法

typedef struct ta_cv_resize_s {
int start_x;
int start_y;
int in_width;
int in_height;
int out_width;
int out_height;
} ta_cv_resize_t;

typedef struct ta_cv_resize_image_s {
ta_cv_resize_t *resize_img_attr;
unsigned int interpolation;
int stretch_fit;
} ta_cv_resize_image_t;

参数说明

参数名称描述备注
start_xresize 起始 x 坐标
start_yresize 起始 y 坐标
in_width输入图像的 width
in_height输入图像的 height
out_widthresize 后图像的 width
out_heightresize 后图像的 height
interpolation缩图所使用的算法
stretch_fit是否等比例缩放

插值算法枚举

ta_cv_resize_algorithm_t
typedef enum ta_cv_resize_algorithm_e {
TA_CV_INTER_NONE = 0, // 默认为线性插值
TA_CV_INTER_LINEAR,
TA_CV_INTER_LANCZOS,
TA_CV_INTER_NEAREST,
TA_CV_INTER_BILINEAR,
TA_CV_INTER_BICUBIC,
TA_CV_INTER_SPLINE,
TA_CV_INTER_BOX,
TA_CV_INTER_FAST_LINEAR,
TA_CV_INTER_FAST_BICUBIC,
} ta_cv_resize_algorithm_t;

参数说明

枚举值描述
TA_CV_INTER_NONE默认为线性插值
TA_CV_INTER_LINEAR线性插值算法
TA_CV_INTER_LANCZOSLanczos 插值算法
TA_CV_INTER_NEAREST最邻插值算法
TA_CV_INTER_BILINEAR双线性插值算法
TA_CV_INTER_BICUBIC双三次插值算法
TA_CV_INTER_SPLINE样条插值算法
TA_CV_INTER_BOX区域插值算法
TA_CV_INTER_FAST_LINEAR快速线性插值算法
TA_CV_INTER_FAST_BICUBIC快速双三次插值算法

ta_cv_rect_t

语法

typedef struct ta_cv_rect_s {
int start_x;
int start_y;
int crop_w;
int crop_h;
} ta_cv_rect_t;

参数说明

参数名称描述备注
start_xcrop 起始 x 坐标
start_ycrop 起始 y 坐标
crop_wcrop 的宽度
crop_hcrop 的高度

ta_cv_copy_to_t

语法

typedef struct ta_cv_copy_to_s {
int start_x;
int start_y;
} ta_cv_copy_to_t;

参数说明

参数名称描述备注
start_xcopy 至目标图的 x 坐标
start_ycopy 至目标图的 y 坐标

ta_cv_padding_attr_t

语法

typedef struct ta_cv_padding_attr_s {
unsigned int dst_crop_stx;
unsigned int dst_crop_sty;
unsigned int dst_crop_w;
unsigned int dst_crop_h;
} ta_cv_padding_attr_t;

参数说明

参数名称描述备注
dst_crop_stx输出图像 crop 起始 x 坐标
dst_crop_sty输出图像 crop 起始 y 坐标
dst_crop_w输出图像 crop 的宽度
dst_crop_h输出图像 crop 的高度

csc_type_t

语法

typedef enum csc_type_e {
CSC_NONE = 0,
CSC_YCbCr2RGB_BT601, // NV12 转 RGB 的协议
CSC_RGB2YCbCr_BT601,
CSC_YCbCr2RGsB_BT709,
CSC_RGB2YCbCr_BT709,
CSC_YCbCr2RGB_BT2020,
CSC_RGB2YCbCr_BT2020
} csc_type_t;

参数说明

枚举值描述
CSC_NONE无颜色空间转换
CSC_YCbCr2RGB_BT601YCbCr 转 RGB (BT.601)
CSC_RGB2YCbCr_BT601RGB 转 YCbCr (BT.601)
CSC_YCbCr2RGsB_BT709YCbCr 转 RGB (BT.709)
CSC_RGB2YCbCr_BT709RGB 转 YCbCr (BT.709)
CSC_YCbCr2RGB_BT2020YCbCr 转 RGB (BT.2020)
CSC_RGB2YCbCr_BT2020RGB 转 YCbCr (BT.2020)

ta_select_t

语法

typedef enum ta_hw_select_e {
ENABLE_CPU = 0, // 使用 cpu
ENABLE_PPU, // 使用 ppu 计算
ENABLE_PP // 使用 PP 硬件
} ta_hw_select_t;

参数说明

枚举值描述
ENABLE_CPU使用 CPU
ENABLE_PPU使用 PPU 计算
ENABLE_PP使用 PP 硬件

6.2.7 taCV 示例程序

#include "ta_cv_api_ext_c.h"
#include <stdio.h>
#include <string.h>
#include <BufferAllocator/BufferAllocatorWrapper.h>

int main(int argc, const char** argv)
{
int ret = 0;
int width = atoi(argv[2]);
int height = atoi(argv[3]);
int out_width = atoi(argv[4]);
int out_height = atoi(argv[5]);
int format = FORMAT_NV12;
int total_size_in = width * height * 1.5;
int total_size_out = out_width * out_height * 1.5;

unsigned long long physAddr_in = 0;
unsigned long long physAddr_out = 0;
ta_image_t image_in,image_out;
ta_cv_resize_image_t resize_attr = {0};
ta_cv_resize_t resize = {0};

// 初始化 dmabufheap,获取 block
BufferAllocator* dmabuf_allocator = CreateDmabufHeapBufferAllocator();
if (!dmabuf_allocator) {
return -1;
}

unsigned int input_fd = DmabufHeapAlloc(dmabuf_allocator, "carveout-heap", total_size_in);
unsigned int output_fd = DmabufHeapAlloc(dmabuf_allocator, "carveout-heap", total_size_out);
if(input_fd < 0 || output_fd < 0){
FreeDmabufHeapBufferAllocator(dmabuf_allocator);
close(input_fd);
close(output_fd);
return -1;
}
// 创建图像结构体

ret = ta_cv_image_create_ext(height,width,(ta_image_format_ext_t)format,&image_in,input_fd);

ret |= ta_cv_image_create_ext(out_height,out_width,(ta_image_format_ext_t)format,&image_out,output_fd);
if(ret != TACV_SUCCESS){
ta_cv_image_destroy_ext(&image_in);
ta_cv_image_destroy_ext(&image_out);
close(input_fd);
close(output_fd);
return -1;
}
FILE *fd = fopen(argv[1], "rb");
if(fd == NULL){
goto failed;
}
fread(image_in.frame.data[0], total_size_in, 1, fd);
fclose(fd);


resize.in_height = height;
resize.in_width = width;
resize.out_height = out_height;
resize.out_width = out_width;
resize.start_x = 0;
resize.start_y = 0;
resize_attr.resize_img_attr = &resize;
resize_attr.interpolation = 3;

// 调用函数
ret = ta_cv_image_resize(&resize_attr, image_in, image_out);

fd = fopen("resize_output.bin", "wb");
fwrite(image_out.frame.data[0], total_size_out, 1, fd);
fclose(fd);
failed:
// 释放 block
ta_cv_image_destroy_ext(&image_in);
ta_cv_image_destroy_ext(&image_out);
close(input_fd);
close(output_fd);

return ret;
}

6.3 taRuntime 接口详解

6.3.1 ta_runtime_init

描述

实现模块初始化流程,为后续模型加载与推理运行做好软硬件准备。

详情

该接口完成硬件和软件相关资源的初始化操作。主要包括初始化 NPU 硬件资源和驱动程序。 本函数应在其他接口调用前执行,每个进程仅需调用一次,且需要与 ta_runtime_deinit 接口配对使用。若未调用该接口即尝试加载模型或进行推理,相关接口会返回失败。

语法

taco_status_t ta_runtime_init();

返回值

错误码描述
0成功
非 0失败

注意事项

  • 支持多进程、多线程,每个进程都应调用一次,最先调用的生效
  • 每个进程仅调用一次即可,不应每个线程都调用

6.3.2 ta_runtime_deinit

描述

实现模块反初始化流程,包括释放已分配的各种资源,关闭 NPU 服务。

详情

本接口用于在应用程序退出前对各种资源进行清理,释放初始化和运行阶段所申请的资源。

语法

taco_status_t ta_runtime_deinit();

返回值

错误码描述
0成功
非 0失败

注意事项

  • 支持多进程、多线程,每个进程都应调用一次,最后调用的生效
  • 每个进程仅调用一次即可,不应每个线程都调用

6.3.3 ta_runtime_load_model_from_file

描述

从文件系统中读取模型文件,解析文件信息并创建可在板端运行的网络模型。

详情

接口从文件系统中读取的是 NB 格式的模型文件,加载到系统域内存区。接口内部对 NB 文件进行解析,提取出 NPU 推理所需的指令流和权重数据,保存在 NN 域内存区。文件解析完毕后,系统域的输入数据就不再需要了,用户可以释放该 buffer。

语法

taco_status_t ta_runtime_load_model_from_file(
ta_runtime_context *context,
const char *model_path,
uint32_t core_index);

参数说明

参数描述输入/输出
contextta_runtime_context 类型的结构体指针。该结构体由 SDK 内部逻辑维护,用户需要在相关接口中传递该指针,除此之外无需使用该结构体输入/输出
model_path模型路径输入
core_indexNPU 设备支持两个 cluster,编号为 0 和 1。此参数用于指定模型部署至哪个 cluster 上运行。若模型类型为 dual-core,则该参数必须设置为 0输入

返回值

错误码描述
0成功
非 0失败

注意事项

  • 确保在调用该接口前某个进程执行了模块初始化操作

6.3.4 ta_runtime_load_model_at_ddr

描述

从 DDR 内存中读取模型信息,解析并创建可在板端运行的网络。

详情

接口从系统域输入 buffer 读取的是 NB 格式的模型信息,接口内部对 NB 信息进行解析,提取出 NPU 推理所需的指令流和权重数据,保存在 NN 域内存区。解析完成后,系统域输入 buffer 就不再需要了,用户可以释放该 buffer。

语法

taco_status_t ta_runtime_load_model_at_ddr(
ta_runtime_context *context,
void* model,
const uint64_t model_size,
uint32_t core_index);

参数说明

参数描述输入/输出
contextta_runtime_load_model_from_file输入
model模型数据指针输入
model_size模型尺寸输入
core_indexta_runtime_load_model_from_file输入

返回值

错误码描述
0成功
非 0失败

注意事项

  • 确保在调用该接口前某个进程执行了模块初始化操作

6.3.5 ta_runtime_query

描述

查询模型输入输出信息、模型推理的总时间,以及模型相关信息。

语法

taco_status_t ta_runtime_query(
ta_runtime_context *context,
const uint32_t property,
void *value);

参数说明

参数描述输入/输出
contextta_runtime_load_model_from_file输入
property查询指令输入
value存放返回结果的 buffer 地址输入/输出

返回值

错误码描述
0成功
非 0失败

查询命令

查询命令描述返回值类型
TACONN_QUERY_DRIVER_VERSION查询驱动版本uint32_t
TACONN_QUERY_IN_OUT_NUM查询输入输出 tensor 个数taconn_input_ouput_num_t
TACONN_QUERY_INPUT_ATTR查询输入 tensor 属性taconn_inout_attr_t
TACONN_QUERY_OUTPUT_ATTR查询输出 tensor 属性taconn_inout_attr_t
TACONN_QUERY_LAYER_COUNT查询网络模型总层数uint32_t
TACONN_QUERY_NETWORK_NAME查询网络名称char[]
TACONN_QUERY_PROFILING查询模型推理性能数据taconn_profile_t
TACONN_NETWORK_MEMORY_POOL_SIZE查询模型占用的 video_memory 内存大小taconn_memory_size_t

6.3.6 ta_runtime_set_input_cva

描述

用于设置模型的输入数据(图像或张量),输入地址类型为 CPU 虚拟地址,支持拷贝和映射两种访问方式。

详情

所谓输入数据,具体是指模型的第一层算子所需的输入数据,它的具体形式取决于模型的要求。多数模型需要一幅图像作为输入,有些模型可能需要两幅或者更多图像。而图像格式可以有 NV12、RGB、Tensor 等多种选项,图像的数据精度一般是 INT8。 该接口支持一次设置多个输入,因此用户需要提供一个 taconn_input_t 结构体的数组,并且确保结构体的所有参数均已正确赋值,未使用的参数应清零。 如果使用拷贝方式,本接口会在 NN 域申请一个 buffer(涉及存储空间+虚拟地址两种资源),将输入数据拷贝到 NN 域 buffer,所以接口返回后输入 buffer 可以立即释放。NN 域 buffer 会在推理结束后由 SDK 自动释放。 如果使用映射方式,本接口会在 NN 域申请一段虚拟地址,并与输入数据所在的内存页面建立映射关系。接口返回后输入 buffer 不能立即释放,必须等推理结束后才能释放。NN 域虚拟地址会在推理结束后由 SDK 自动释放。

语法

taco_status_t ta_runtime_set_input_cva(
ta_runtime_context *context,
uint32_t input_num,
taconn_input_t *input);

参数说明

参数描述输入/输出
contextta_runtime_load_model_from_file输入
input_num模型输入的个数输入
input指针,指向一个taconn_input_t类型的数组输入

返回值

错误码描述
0成功
非 0失败

注意事项

  • 结构体在赋值前应整体清零,在参数有误的情况下,清零有利于故障现象的一致性
  • 输入数量不应超过模型所需的输入个数,否则接口会报错
  • 输入数据的地址必须是 256 对齐(地址指针的低 8 位全为 0),否则接口会报错

6.3.7 ta_runtime_set_input_pha

描述

用于设置模型的输入数据,输入地址类型为物理地址。

详情

本接口内部将输入的物理地址映射为 NPU 虚拟地址,一次推理结束后,接口内部会尝试把虚拟地址缓存到内部查找表中,待模块卸载时统一释放。 该接口支持多个输入,因此用户需要提供一个 taconn_input_phy_t 结构体的数组,并且确保结构体的所有参数均已正确赋值,未使用的参数应清零。 本接口内部在 NN 域申请一段虚拟地址,并与输入数据所在的内存页面建立映射关系。接口返回后输入 buffer 不能立即释放,必须等推理结束后才能释放。NN 域虚拟地址会优先缓存在接口内部的查找表中,待模块销毁时由 SDK 自动释放;如果未能缓存到查找表则会立即释放。

语法

taco_status_t ta_runtime_set_input_pha(
ta_runtime_context *context,
uint32_t input_num,
taconn_input_phy_t *input);

参数说明

参数描述输入/输出
contextta_runtime_load_model_from_file输入
input_num模型输入的个数输入
input指向taconn_input_phy_t类型结构体数组。每个元素代表一个输入的物理地址段信息,包括物理地址表和对应大小表输入

返回值

错误码描述
0成功
非 0失败

注意事项

  • 用户应在开始推理前完成输入 buffer 的设置,如果设置不全,推理接口会报错
  • 本接口允许用户针对同一目标通道多次设置输入 buffer,旧的设置自动失效
  • 结构体在赋值前应整体清零,在参数有误的情况下,清零有利于故障现象的一致性
  • 输入数量不应超过模型所需的输入个数,否则接口会报错
  • 输入数据的地址必须是 256 对齐(地址指针的低 8 位全为 0),否则接口会报错

6.3.8 ta_runtime_create_buffer

描述

用于在 NN 域创建一个保存推理输出结果的缓冲区。

详情

本接口与 ta_runtime_set_output() 接口配合使用,作为该接口的前序接口,用于准备模型输出 buffer。 用户在调用本接口时,仅需传入所需 buffer 的大小,接口内部会自动分配内存并填充taconn_buffer_t结构体内容,包括数据指针、buffer size 等信息。结构体 data 字段指向的地址是一个可供 CPU 访问的虚拟地址指针,用户可通过该指针读取推理输出结果。

语法

taco_status_t ta_runtime_create_buffer(
ta_runtime_context *context,
uint32_t size,
taconn_buffer_t *buffer);

参数说明

参数描述输入/输出
contextta_runtime_load_model_from_file输入
size需要创建的 buffer 大小输入
buffer指针,指向一个taconn_buffer_t结构体输出

返回值

错误码描述
0成功
非 0失败

注意事项

  • 用户需要根据模型情况计算 buffer 大小,如果 buffer 不够大,后序接口会失败
  • 本接口应与 ta_runtime_destroy_buffer() 接口成对使用

6.3.9 ta_runtime_destroy_buffer

描述

销毁由 ta_runtime_create_buffer() 创建的 NN 域 buffer,并释放对应的 CPU 虚拟地址资源。

语法

taco_status_t ta_runtime_destroy_buffer(
ta_runtime_context *context,
taconn_buffer_t *buffer);

参数说明

参数描述输入/输出
contextta_runtime_load_model_from_file输入
buffer指向待销毁的taconn_buffer_t类型结构体。该结构体需由 ta_runtime_create_buffer() 创建,函数调用后其内部数据指针即失效输入&输出

返回值

错误码描述
0成功
非 0失败

注意事项

  • 本接口应与 ta_runtime_create_buffer() 接口成对使用
  • 用户程序应在销毁前停止访问 taconn_buffer_t 的成员变量
  • 应避免多次调用销毁同一 buffer 结构体,或销毁未初始化的 buffer,否则产生 UB 行为

6.3.10 ta_runtime_set_output

描述

设置模型推理的输出 buffer。

详情

本接口为模型的指定输出通道设置一个 NN 域输出 buffer,模型推理结束后,用户通过 NN 域 buffer 对应的 CPU 虚拟地址读取推理结果。 本接口与 ta_runtime_create_buffer() 接口配合使用,作为该接口的后序接口。

语法

taco_status_t ta_runtime_set_output(
ta_runtime_context *context,
uint32_t output_num,
taconn_buffer_t *buffer);

参数说明

参数描述输入/输出
contextta_runtime_load_model_from_file输入
output_num模型的输出个数输入
buffertaconn_buffer_t结构体指针输入

返回值

错误码描述
0成功
非 0失败

注意事项

  • 用户应在开始推理前设置输出 buffer,否则推理接口会报错

6.3.11 ta_runtime_invalidate_buffer

描述

将 CPU cache 中与 NN 域 buffer 对应的虚拟地址标记为 invalid,确保下次会从 DDR 中读取数据。

详情

NPU 完成推理后,用户程序读取推理结果前需调用本接口,确保 CPU 能够读取到 DDR 中的最新数据,而不是从缓存中读取旧数据。

语法

taco_status_t ta_runtime_invalidate_buffer(
ta_runtime_context *context,
taconn_buffer_t *buffer);

参数说明

参数描述输入/输出
contextta_runtime_load_model_from_file输入
buffer指向taconn_buffer_t类型结构体的指针,表示待刷新缓存的一块 NN 域缓冲区。该结构体应由 ta_runtime_create_buffer() 创建并合法初始化输入

返回值

错误码描述
0成功
非 0失败

6.3.12 ta_runtime_run_network

描述

执行一次模型推理。

详情

在调用本接口进行推理前,需要先设置好模型的输入输出 buffer。

语法

taco_status_t ta_runtime_run_network(ta_runtime_context *context);

参数说明

参数描述输入/输出
contextta_runtime_load_model_from_file输入

返回值

错误码描述
0成功
非 0失败

6.3.13 ta_runtime_destroy_context

描述

销毁 NNRT 上下文对象,并释放其关联的所有资源。

详情

该接口用于释放上下文对象 ta_runtime_context 及其内部管理的所有资源。 调用后,传入的 context 指针将被置为 0,表示已无效,不可再被用于任何 NNRT 操作。

语法

taco_status_t ta_runtime_destroy_context(ta_runtime_context *context);

参数说明

参数描述输入/输出
context指向要销毁的 ta_runtime_context 结构体指针输入/输出

返回值

错误码描述
0成功
非 0失败

6.3.14 taRuntime结构体说明

taconn_input_ouput_num_t

结构体 taconn_input_ouput_num_t 用来表示输入输出 tensor 个数,其结构体成员变量如下表所示:

成员变量数据类型含义
input_numuint32_t输入 tensor 个数
output_numuint32_t输出 tensor 个数
taconn_inout_attr_t

结构体 taconn_inout_attr_t 用来表示输入输出 tensor 属性,包含了输入输出的维度、数据类型、量化格式以及量化参数等,其结构体成员变量如下表所示:

成员变量数据类型含义
indexuint32_t输入输出索引
dim_countuint32_t输入或输出 tensor 的维度数量
dim_sizeunsigned long输入输出 tensor 在每个维度上的大小
data_formatuint32_t输入或者输出数据的格式
quant_formatuint32_t输入输出 tensor 的量化类型
quant_dataunion输入输出的量化数据
quant_data.dfp.fixed_point_posint32_t量化格式为 dfp 时,量化参数
quant_data.affine.tf_scalefloat量化格式为 affine 时,scale 参数
quant_data.affine.tf_zero_pointint32_t量化格式为 affine 时,zero point 参数
taconn_input_t

结构体 taconn_input_t 表示模型的一个数据输入,用来作为参数传给 taco_nnrt_set_input_cva

结构体定义如下:

成员变量数据类型含义
indexuint32_t输入索引
datavoid *模型输入数据地址
sizeuint32_tbuffer 大小
taconn_input_phy_t

结构体 taconn_input_phy_t 表示模型的一个数据输入,用来作为参数传给 taco_nnrt_set_input_pha

成员变量数据类型含义
physical_numuint32_t物理地址数量。表示 physical_tablesize_table 中有效条目的个数。
physical_tableuint64_t *指向物理地址数组的指针,每个地址为 64 位物理地址。可用于直接映射到 NN 域内存。
size_tableuint32_t *描述每段物理内存的有效数据长度。
taconn_buffer_t

结构体 taconn_buffer_t 表示一个创建的 nn buffer,用来作为参数传给 taco_nnrt_create_buffertaco_nnrt_set_output

成员变量数据类型含义
datavoid *NN 域 buffer 对应的 cpu 虚指针
sizeuint32_tbuffer 大小
taconn_profile_t

结构体 taconn_profile_t 用于表示模型在推理时的性能指标。

成员变量数据类型含义
inference_timeuint32_t模型推理一帧数据的总耗时
total_cycleuint32_t模型推理一帧使用的 cycle 总数

6.4 taOpenCV 接口说明

TACO SDK提供的taOpenCV基于社区版OpenCV进行扩展,并对部分常用图像处理与视觉算法实现了硬件加速和向量加速。其中一部分优化基于玄铁的C920 CPU的RVV扩展指令集,对图像缩放、插值滤波、颜色空间变换、通道分离合并、二值化、LK 光流、金字塔等常用算子算法进行了向量加速。另一类优化则面向专用硬件处理路径,对 JPEG 编解码、图像缩放、格式转换及裁剪等功能提供了硬件加速支持

TACO SDK 中提供的 taOpenCV 相关版本信息如下。

OpenCV 版本OS 版本CPU 版本RVV 版本
4.5.4Linux 6.6玄铁 C920V21.0

关于 OpenCV 库的使用说明可参考 「OpenCV 官方网站」,关于 RISC-V RVV 的版本差异情况可参考 「RISC-V 官方 GitHub」

6.4.1 硬件加速内存分配

为支持硬件加速,需要为相关数据分配满足硬件访问要求的内存。在本方案中,对 OpenCV 的 MatAllocator 分配机制进行了扩展,实现了其子类 DmaBufMatAllocator。该分配器基于底层 dmabufheap 接口申请可供硬件直接访问的内存资源,并重写了 allocate 方法,在分配过程中以 dmaMalloc 替代默认的 fastMalloc,同时完成缓冲区描述符及相关物理地址信息的初始化与绑定。 在 OpenCV 内部流程中,可通过校验该内存块关联的描述符等元数据,识别当前 Mat 是否具备硬件加速所需的内存属性,从而决定是否进入对应的硬件加速处理路径。

相关结构体扩展
struct CV_EXPORTS UMatData
{
...
uint64 addr;
unsigned int blk_id;
...
}

u->addr = physAddr;
u->blk_id = dmabuf_fd;

其中:

  • addr:物理地址
  • blk_id:内存块描述符(dmabuf fd
获取dmabuf heap分配器
int width = 640;
int height = 640;
Mat img;
//方法一
img.allocator = hal::getAllocator();
img.create(height*3/2,width,CV_8UC1);
//方法二
Mat::setDefaultAllocator(hal::getAllocator());//全局内存分配器设置
Mat img2(height*3/2,width,CV_8UC1);
  • 上述方式可为 Mat对象指定Dmabuf heap分配器,以便后续硬件加速接口直接使用,推荐使用方法一。

6.4.2 taOpenCV API 功能扩展

OpenCV 原生支持的一些 API 函数,如 imread()imwrite(),可以自动识别 JPEG 格式并进行编解码处理。SDK 对这些 API 函数进行了扩展,使其能够自动选择合适的芯片硬件来完成任务。

Mat(AVFrame *frame)

描述 通过 AVFrame 创建 Mat 对象。 参数说明

参数描述输入/输出
frame与ffmpeg 的 AVFrame 对象对应。输入

返回值

返回Mat 对象。

imread( const String& filename, int flags = IMREAD_COLOR )

描述

读取并解码输入的JPEG图片,并返回解码后的Mat对象。 当前仅对输入的JPEG图片提供硬件加速支持,输出格式支持RGBNV12

参数说明

参数描述输入/输出
filename输入的文件名输入
flags输入的标志位输入

自定义flags说明

枚举值描述
IMREAD_COLOR_YUV将 JPEG 解码结果以 NV12 格式存入返回的 Mat 对象中。
IMREAD_RETRY_SOFTDEC默认优先使用硬件解码;当希望强制回退时,可设置该标志位以启用软件解码。

返回值

返回Mat 对象。

注意

  • 接口解码JPEG文件时默认硬件加速
  • 若需强制回退成软件解码,可将flags标志位设置成IMREAD_COLOR|IMREAD_RETRY_SOFTDEC
  • 将标志位设置为IMREAD_COLOR_YUV解码出NV12格式图像。

示例

Mat img = imread("test.jpg");//JPEG解码输出bgr格式
Mat img = imread("test.jpg",IMREAD_COLOR_YUV);//JPEG解码输出NV12格式
Mat img = imread("test.jpg",IMREAD_COLOR|IMREAD_RETRY_SOFTDEC);不使用硬件解码加速
imwrite( const String& filename, InputArray img,const std::vector<int>& params = std::vector<int>());

描述

对输入图像进行编码并保存为指定文件格式。 当前仅支持 基于 NV12 输入的 JPEG 编码硬件加速。

参数说明

参数描述输入/输出
filename输入的文件名输入
img输入的mat输入
params编码参数输入

返回值

参数描述
true成功
flase失败

注意

  • 当 params 设置为 IMWRITE_JPEG_SAMPLING_FACTORIMWRITE_JPEG_SAMPLING_FACTOR_NV12 对应参数对时,启用 NV12 格式 JPEG 编码硬件加速。

示例

vector<int> param;
param.push_back(cv::IMWRITE_JPEG_SAMPLING_FACTOR); // 指定为NV12格式
param.push_back(cv::IMWRITE_JPEG_SAMPLING_FACTOR_NV12);
Mat img;
img.allocator = hal::getAllocator();
img.create(640*3/2,640,CV_8UC1);
imwrite("test.jpg",img,param);
resize( InputArray _src, OutputArray _dst, Size dsize,double inv_scale_x, double inv_scale_y, int interpolation )

描述

对图像进行缩放处理。当前对 NV12 格式图像的缩放提供硬件加速支持。

参数说明

参数名称描述输入/输出备注
_src输入图像输入需为 NV12 格式以启用硬件加速
_dst输出图像输出需预先分配足够大小的内存
dsize输出尺寸,格式 (宽,高)输入设为 None 则由 fx/fy 计算
inv_scale_x水平缩放因子输入
inv_scale_y垂直缩放因子输入
interpolation插值算法选择输入默认值为 INTER_LINEAR

插值算法

枚举值描述
INTER_NEAREST最邻插值算法
INTER_LINEAR线性插值算法

返回值

无返回值(void

注意事项

  • 当前仅支持 NV12 格式图像使用硬件加速,其他格式将回退到软件实现
  • 当前硬件加速路径仅支持缩小(downscale),不支持放大(upscale

使用示例

// JPEG 解码输出 NV12 格式图像
cv::Mat img = cv::imread("test.jpg", cv::IMREAD_COLOR | cv::IMREAD_COLOR_YUV);

// 创建输出图像,使用 DmaBuf heap 分配器以启用硬件加速
cv::Mat img_out;
img_out.allocator = cv::hal::getAllocator();
img_out.create(640 * 3 / 2, 640, CV_8UC1);

// 执行缩放操作(输入分辨率需大于输出分辨率)
cv::resize(img, img_out, cv::Size(640, 640));

// 保存结果
cv::imwrite("output.jpg", img_out);
cvtColor(InputArray _src,OutputArray _dst,int code,int dcn = 0)

描述

对输入图像进行颜色空间格式转换。当前对 NV12RGB24/BGR24 的场景提供硬件加速支持。

参数说明

参数名称描述输入/输出备注
_src输入图像输入
_dst输出图像输出
code色彩转换码输入
dcn输出图像通道数输入

注意事项

  • 仅当 codeCOLOR_YUV2RGB_NV12COLOR_YUV2BGR_NV12 时,才会启用硬件加速。
  • 当前硬件加速路径仅支持 NV12 -> RGB24/BGR24 转换。

使用示例

Mat img = imread("test.jpg", IMREAD_COLOR_YUV);  // JPEG 解码输出 NV12 格式
Mat img_out;
img_out.allocator = hal::getAllocator();
img_out.create(640, 640, CV_8UC3);
cvtColor(img, img_out, COLOR_YUV2RGB_NV12);
Crop(Mat &m,OutputArray dst,Rect rect)

描述

对图像进行裁剪。当前只对 NV12 格式图像的裁剪提供硬件加速支持。

参数说明

参数名称描述输入/输出备注
m输入图像输入
dst输出图像输出
rect裁剪区域信息输入

注意事项

  • 只支持 NV12 的图片格式进行硬件加速。

使用示例

Mat img = imread("test.jpg", IMREAD_COLOR_YUV);  // JPEG 解码输出 NV12 格式
Mat img_out;
img_out.allocator = hal::getAllocator();
img_out.create(640*3/2,640,CV_8UC1);
Crop(img, img_out, Rect(0, 0, 640, 640));

6.4.3 RVV 加速接口

TACO SDK 提供的 taOpenCV 库对部分接口进行了优化,其中,有些接口是使用了 RISC-V RVV 向量指令集实现的加速,下表对此类接口进行了汇总。

优化算子支持数据类型参数说明
addu8/s8/u16/s16/s32/f32/f64两个数组逐个元素做加运算
subu8/s8/u16/s16/s32/f32/f64两个数组逐个元素做减运算
maxu8/s8/u16/s16/s32/f32/f64两个数组逐个元素求最大值
minu8/s8/u16/s16/s32/f32/f64两个数组逐个元素求最小值
mulu8/s8/u16/s16/s32/f32/f64两个数组逐个元素做乘法运算
absdiffu8/s8/u16/s16/s32/f32/f64两个数组差值的绝对值(求帧差)
divu8/s8/u16/s16/s32/f32/f64两个数组逐个元素做除法运算
recipu8/s8/u16/s16/s32/f32/f64数组元素的倒数运算
addWeightedu8/s8/u16/s16/s32/f32/f64两个数组逐个元素做加权相加运算(alpha 运算)
and/or/xor/notu8按位做逻辑操作(与/或/异或/非)
cmpu8/s8/u16/s16/s32/f32/f64数组元素比较运算
splitu8/s8/u16/s32/s64将一个多通道数组分割成多个单通道数组
mergeu8/s8/u16/s32/s64将几个单通道数组合并成一个多通道数组
fastAtanf32/f64快速计算反正切值
BoxFilteru83x3, cn=1, norm
Resizeu8INTER_LINEAR, Area, Nearest
Thresholdu8/s8/u16/s16/f32/f64图像阈值化
Sobelu8->s16, u8->f32Sobel 边缘检测算子,3x3, cn=1; 5x5, cn=1
MedianBluru83x3, 5x5
BGRtoBGRu8bgr/bgra/rgb/rgba
BGRtoBGR5x5u8bgr/bgra/rgb/rgba->bgr565/bgr555
BGR5x5toBGRu8bgr565/bgr555->bgr/bgra/rgb/rgba
BGRtoGrayu8bgr/bgra/rgb/rgba->gray
GraytoBGRu8gray->bgr/bgra/rgb/rgba
BGRtoYUVu8bgr/bgra/rgb/rgba->YUV Planar
YUVtoBGRu8YUV Planar->bgr/bgra/rgb/rgba
BGRtoXYZu8bgr/bgra/rgb/rgba->XYZ
XYZtoBGRu8XYZ->bgr/bgra/rgb/rgba
TwoPlaneYUVtoBGRu8YUV Semi-Planar (NV12/NV21/etc.)
ThreePlaneYUVtoBGRu8YUV Planar (YUV420P/etc.)
BGRtoThreePlaneYUVu8YUV Planar (YUV420P/etc.)
BGRtoTwoPlaneYUVu8YUV Semi-Planar (NV12/NV21/etc.)
OnePlaneYUVtoBGRu8单平面 YUV 转 BGR
Dilateu83x3, cn=1,4; 4x4, cn=1; 5x5, cn=1; 15x15, cn=1
Erodeu83x3, cn=1,4; 4x4, cn=1; 5x5, cn=1; 15x15, cn=1
WarpAffineu8INTER_LINEAR (BORDER_REPLIATE/CONSTANT) NEAREST (BORDER_REPLIATE/CONSTANT)
WarpPrespectiveu8INTER_LINEAR (BORDER_REPLIATE/CONSTANT)
GaussianBluru87x7, cn=1
PyrDownu8BORDER_CONSTANT, cn=1/2/3/4
OptFlowPyrLKu8光流金字塔 LK 算法
countNTaonZerou8cn=1
convertu8/s8/u16/s16/s32/f32/f64数据类型转换
norm1u8L2, no mask
minMaxLof32max_val, no mask
calcMinEigenValf32计算最小特征值
calcHarrisf32Harris 角点检测

6.4.4 taOpenCV 示例程序

#include "opencv2/opencv.hpp"
#include <iostream>

//推荐用法
int main( int argc, const char** argv )
{
std::string filename = "./fruits.jpg";
image = cv::imread(filename,IMREAD_COLOR_YUV);
//error handling skipped
Crop(image,);
Mat scaled;
scaled.allocator = hal::getAllocator();
scaled.create(100 * 3 /2,100,CV_8UC1);

cv::resize(image_nv12, scaled, cv::Size(100,100), 0, 0, cv::INTER_LINEAR);

vector<int> param;
param.push_back(cv::IMWRITE_JPEG_SAMPLING_FACTOR); // 指定为NV12格式
param.push_back(cv::IMWRITE_JPEG_SAMPLING_FACTOR_NV12);
cv::imwrite("./output.jpg", scaled, param);

return 0;
}

6.5 taFFmpeg 接口说明

TACO SDK 提供的 taFFmpeg 基于 FFmpeg 官方的 4.3.2 版本,我们对 FFmpeg 进行了一些扩展,使其能够自动选择合适的芯片硬件来完成任务。前文已经对 taFFmpeg 有了一些描述,这个章节对支持的编解码器进行补充说明。

6.5.1 视频解码器

用户可通过如下命令来查询 taFFmpeg 支持的解码器。

ffmpeg -decoders

其结果中应包含由 TACO SDK 提供的硬件加速版 H.264 解码器,名称为 h264_taco。 用户可以通过如下命令行查询硬件解码器提供的一些额外选项:

ffmpeg -h decoder=h264_taco
ffmpeg -h decoder=hevc_taco

目前已经支持的选项有:

参数名称功能描述取值范围默认值
vdec_output_semi_planar指定输出图像的平面格式0 ~ 输出 YUV420 Planar 图像;1 ~ 输出 YUV420 Semi-planar 图像0
vdec_extra_frame_buffer_num额外提供的帧缓存数量大于等于 1 的整数2
vdec_stream_addr_typeBitstream 数据指针的类型0 ~ 物理地址,页面连续;1 ~ 虚拟地址,页面连续;2 ~ 虚拟地址,页面不保证连续0
vdec_fps_decimation解码后哪些帧需要写入 DDR0 ~ 全部写入 DDR;1 ~ 写一帧跳一帧;2 ~ 写一帧跳两帧0

这些选项可以使用 taFFmpeg 提供的 av_dict_set() 接口进行设置。

6.5.2 视频编码器

用户可通过如下命令来查询 taFFmpeg 支持的编码器。

ffmpeg -encoders

其结果中应包含由 TACO SDK 提供的硬件加速版 H.264 编码器,名称为 h264_taco。 用户可以通过如下命令行查询硬件编码器提供的一些额外选项:

ffmpeg -h encoder=h264_taco

目前已经支持的选项有:

参数名称功能描述取值范围默认值
venc_quality_mode指定编码的质量模式0 ~ 速度优先,质量低;1 ~ 均衡模式;2 ~ 质量优先,速度低2
venc_gop_size设置一个 GOP 包含的帧数大于等于 1 的整数30
venc_rc_mode码率控制算法0 ~ fixed qp;1 ~ vbr;2 ~ cbr2
venc_yuv_addr_typeYUV 数据指针的类型0 ~ 物理地址,页面连续;1 ~ 虚拟地址,页面连续;2 ~ 虚拟地址,页面不保证连续0

这些选项可以使用 taFFmpeg 提供的 av_dict_set() 接口进行设置。

6.5.3 JPEG 解码器

用户可以通过如下命令行查询硬件 JPEG 解码器是否已安装:

ffmpeg -decoders | grep jpeg_taco

用户可以通过如下命令行查询 JPEG 硬件解码器提供的一些额外选项:

ffmpeg -h decoder=jpeg_taco

目前已经支持的选项有:

参数名称功能描述取值范围默认值
jdec_bs_buffer_size设置输入流缓冲区的大小大于 0 的整数2
jdec_extra_frame_buffer_num额外提供的帧缓存数量大于等于 0 的整数,建议:Jpeg 可以为 0,mjpeg 大于 02
jdec_stream_addr_typeBitstream 数据指针的类型0 ~ 物理地址,页面连续;1 ~ 虚拟地址,页面连续;2 ~ 虚拟地址,页面不保证连续0

这些选项可以使用 taFFmpeg 提供的 av_dict_set() 接口进行设置。

6.5.4 JPEG 编码器

用户可以通过如下命令行查询硬件编码器提供的一些额外选项:

ffmpeg -encoders | grep jpeg_taco

用户可以通过如下命令行查询 JPEG 硬件解码器提供的一些额外选项:

ffmpeg -h encoder=jpeg_taco

目前已经支持的选项有:

参数名称功能描述取值范围默认值
jenc_bs_buffer_size设置输出流缓冲区的大小大于 0 的整数500*1024
jenc_yuv_addr_typeYUV 数据指针的类型0 ~ 物理地址,页面连续;1 ~ 虚拟地址,页面连续;2 ~ 虚拟地址,页面不保证连续0

6.5.5 结构体定义

AVFrame 结构体的定义位于 libavutil/frame.h 中,它封装了一个视频帧的多种信息,包括图像数据(编码前或解码后的未压缩数据)、时间戳、像素格式、分辨率等。

下面是一些关键字段的介绍:

  • data: 指针数组,每个指针指向视频帧数据的一个颜色通道(数据平面)。例如,对于 ffmpeg 默认的 YUV420P 格式,data[0] 指向 Y 分量,data[1]data[2] 分别指向 U 和 V 分量
  • linesize: 数组,对于图像的每个颜色通道,记录它的一行数据在内存中实际占用的字节数。它的大小取决于像素格式以及数据对齐要求。而数据对齐要求一般是源于生成或者消费这帧图像的硬件的特性
  • format: 视频帧的像素格式(例如 AV_PIX_FMT_YUV420P
  • width, height: 视频帧的宽度和高度
  • pts, pkt_dts: 时间戳信息,用于表示帧的显示时间

在使用 taFFmpeg 进行视频处理时,通常会涉及到以下接口:

  1. 解码: 使用 avcodec_receive_frame() 接口从解码器获取解码后的视频帧
  2. 处理: 使用 sws_scale() 接口对 AVFrame 中的数据进行缩放、裁剪或格式转换等视频处理操作
  3. 编码: 使用 avcodec_send_frame() 接口将处理后的 AVFrame 帧编码为压缩格式
  4. 释放: 使用 av_frame_free() 释放 AVFrame 结构体占用的内存

AVPacket 是 taFFmpeg 中很重要的一个数据结构,其中 A 代表 Audio,V 代表 Video。AVPacket 用于保存解复用之后、解压缩之前的音视频数据,以及关于这些数据的一些附加信息(side data),例如,显示时间戳(pts)、解码时间戳(dts)、数据时长(duration)、所在流媒体的索引(stream_index)等。

在使用 AVPacket 时有几个重要事项需要注意:

  1. AVPacket 的本质是一个数据描述体,它本身并不随身携带媒体数据,而是通过 data 指针指向音视频数据的缓存位置。所以,当对 AVPacket 结构体进行复制的时候,它所描述的音视频数据并没有被复制
  2. AVPacket 结构体描述视频时,它通常只包含一个完整的 Frame,而音频则有可能包含多个 Frame
  3. 允许存在一种特殊的 AVPacket,它只含有附加信息(side data)而没有音视频数据(data)

6.6 ta-vo 接口说明

6.6.1 设备管理 (ta_vo_dev)

6.6.1.1 ta_vo_dev_create()

描述

创建视频输出设备上下文,并进行设备初始化。

语法

ta_vo_dev_ctx *ta_vo_dev_create(ta_vo_dev dev);

参数说明

参数类型说明
devta_vo_dev视频输出设备标识,指定要创建的设备类型。

返回值

返回值描述
指向新创建的 ta_vo_dev_ctx 结构体的指针成功
NULL失败

6.6.1.2 ta_vo_dev_set_attr()

描述

设置视频输出设备的公共属性。

语法

int ta_vo_dev_set_attr(ta_vo_dev_ctx *dev_ctx, const ta_vo_dev_attr *attr);

参数说明

参数类型说明
dev_ctxta_vo_dev_ctx *视频输出设备上下文指针
attrconst ta_vo_dev_attr *设备属性结构体指针,包含设备配置参数

返回值

返回值描述
0成功
非0失败

6.6.1.3 ta_vo_dev_get_attr()

描述

获取视频输出设备的公共属性。

语法

int ta_vo_dev_get_attr(ta_vo_dev_ctx *dev_ctx, ta_vo_dev_attr **attr);

参数说明

参数类型说明
dev_ctxta_vo_dev_ctx *视频输出设备上下文指针
attrta_vo_dev_attr **用于接收设备属性结构体指针的二级指针

返回值

返回值描述
0成功
非0失败

6.6.2 图层管理 (ta_vo_layer)

6.6.2.1 ta_vo_layer_set_attr()

描述

设置图层属性,并进行硬件初始化和资源配置。

语法

int ta_vo_layer_set_attr(ta_vo_layer_ctx *layer_ctx, const ta_vo_layer_attr *layer_attr);

参数说明

参数类型说明
layer_ctxta_vo_layer_ctx *视频图层上下文指针
layer_attrconst ta_vo_layer_attr *图层属性结构体指针,包含图层配置参数

返回值

返回值描述
0成功
负错误码(-ENODEV, -ENOMEM, ... )失败(帧缓冲设备未找到或打开失败, 内存分配失败, ...)

6.6.2.2 ta_vo_layer_get_attr()

描述

获取视频图层的属性。

语法

int ta_vo_layer_get_attr(ta_vo_layer_ctx *layer_ctx, ta_vo_layer_attr *layer_attr);

参数说明

参数类型说明
layer_ctxta_vo_layer_ctx *视频图层上下文指针
layer_attrta_vo_layer_attr *图层属性结构体指针,用于接收图层配置参数

返回值

返回值描述
0成功
非0失败

6.6.2.3 ta_vo_layer_create()

描述

创建并初始化一个图层上下文。

语法

ta_vo_layer_ctx *ta_vo_layer_create(ta_vo_layer layer);

参数说明

参数类型说明
layerta_vo_layer图层标识,指定要创建的图层号。取值范围参考 ta_vo_layer 枚举定义

返回值

返回值描述
ta_vo_layer_ctx * (非NULL)成功,返回指向新创建的图层上下文结构体的指针
NULL失败,内存分配失败(通过日志输出错误信息)

6.6.2.4 ta_vo_layer_destroy()

描述

销毁视频图层上下文,释放所有相关资源。

语法

int ta_vo_layer_destroy(ta_vo_layer_ctx *layer_ctx);

参数说明

参数类型说明
layer_ctxta_vo_layer_ctx *要销毁的视频图层上下文指针

返回值

返回值描述
0成功
非0失败

6.6.2.5 ta_vo_layer_enable()

描述

启用视频图层,配置缩放器(如果启用),并启动显示线程。

语法

int ta_vo_layer_enable(ta_vo_layer_ctx *layer_ctx);

参数说明

参数类型说明
layer_ctxta_vo_layer_ctx *视频图层上下文指针

返回值

返回值描述
0成功
-1失败,定时器创建或设置失败

6.6.2.6 ta_vo_layer_bind_to_dev()

描述

绑定视频层或图形层到指定设备。

语法

int ta_vo_layer_bind_to_dev(ta_vo_layer_ctx *layer_ctx, ta_vo_dev_ctx *dev_ctx);

参数说明

参数类型说明
layer_ctxta_vo_layer_ctx *视频图层上下文指针
dev_ctxta_vo_dev_ctx *视频输出设备上下文指针

返回值

返回值描述
0成功
-EPERM失败: dev_ctxlayer_ctxNULL

6.6.3 通道管理 (ta_vo_chn)

6.6.3.1 ta_vo_chn_create()

描述

创建一个视频通道。

语法

ta_vo_chn_ctx *ta_vo_chn_create(ta_vo_chn chn);

参数说明

参数类型说明
chnta_vo_chn通道编号,指定要创建的通道号。取值范围:[0, TA_VO_MAX_CHN_NUMS]

返回值

返回值描述
ta_vo_chn_ctx * (非NULL)成功,返回指向新创建的通道上下文结构体的指针
NULL失败,内存分配失败(通过日志输出错误信息)

6.6.3.2 ta_vo_chn_set_attr()

描述

设置指定视频输出通道的属性,并根据帧率配置定时器。

语法

int ta_vo_chn_set_attr(ta_vo_chn_ctx *chn_ctx, ta_vo_chn_attr *chn_attr);

参数说明

参数类型说明
chn_ctxta_vo_chn_ctx *视频通道上下文指针
chn_attrta_vo_chn_attr *视频通道属性结构体指针,包含帧率等配置参数

返回值

返回值描述
0成功
-1失败,定时器创建或设置失败
0(特殊)当帧率(chn_attr->fps)为0时,立即返回(不创建定时器)

6.6.3.3 ta_vo_chn_bind_to_layer()

描述

将指定输出通道绑定到图层。

语法

int ta_vo_chn_bind_to_layer(ta_vo_chn_ctx *chn_ctx, ta_vo_layer_ctx *layer_ctx);

参数说明

参数类型说明
chn_ctxta_vo_chn_ctx *要绑定的视频通道上下文指针
layer_ctxta_vo_layer_ctx *目标视频图层上下文指针

返回值

返回值描述
0成功
-EPERM失败,通道上下文或图层上下文指针为空

6.6.3.4 ta_vo_chn_send_frame()

描述

将帧数据送入指定视频输出通道进行显示。

语法

int ta_vo_chn_send_frame(ta_vo_chn_ctx *chn_ctx, const ta_vo_frame *frame);

参数说明

参数类型说明
chn_ctxta_vo_chn_ctx *通道上下文指针
frameconst ta_vo_frame *要显示的帧数据指针

返回值

返回值描述
0成功
-1失败,帧数据无效

6.6.4 回写管理 (ta_vo_wb)

6.6.4.1 ta_vo_wb_create()

描述

创建回写设备。

语法

ta_vo_wb_ctx *ta_vo_wb_create(ta_vo_wb wb);

参数说明

参数类型说明
wbta_vo_wb回写设备标识

返回值

返回值描述
ta_vo_wb_ctx * (非NULL)成功,返回指向新创建的回写设备上下文结构体的指针
NULL失败,内存分配失败

6.6.4.2 ta_vo_wb_set_attr()

描述

设置指定回写设备的回写源属性。

语法

int ta_vo_wb_set_attr(ta_vo_wb_ctx *wb_ctx, const ta_vo_wb_attr *wb_attr);

参数说明

参数类型说明
wb_ctxta_vo_wb_ctx *回写设备上下文指针
wb_attrconst ta_vo_wb_attr *回写属性结构体指针,包含回写源等配置参数

返回值

返回值描述
0成功
-1失败: wb_ctxwb_attrNULL

6.6.4.3 ta_vo_wb_enable()

描述

启用指定的回写设备。

语法

int ta_vo_wb_enable(ta_vo_wb_ctx *wb_ctx);

参数说明

参数类型说明
wb_ctxta_vo_wb_ctx *回写设备上下文指针

返回值

返回值描述
0成功

6.6.4.4 ta_vo_wb_bind_to_layer()

描述

将回写设备绑定到指定图层。

语法

int ta_vo_wb_bind_to_layer(ta_vo_wb_ctx *wb_ctx, ta_vo_layer_ctx *layer_ctx);

参数说明

参数类型说明
wb_ctxta_vo_wb_ctx *回写设备上下文指针
layer_ctxta_vo_layer_ctx *目标视频图层上下文指针

返回值

返回值描述
0成功
-1失败: wb_ctxlayer_ctxNULL

6.6.4.5 ta_vo_wb_get_frame()

描述

获取回写视频数据。

语法

ta_vo_wb_frame *ta_vo_wb_get_frame(ta_vo_wb_ctx *wb_ctx);

参数说明

参数类型说明
wb_ctxta_vo_wb_ctx *回写设备上下文指针

返回值

返回值描述
ta_vo_wb_frame * (非NULL)成功,返回指向回写帧结构体的指针
NULL失败: wb_ctxlayer_ctx 无效,或内存分配失败

6.6.4.6 ta_vo_wb_put_frame()

描述

释放回写视频数据。

语法

int ta_vo_wb_put_frame(ta_vo_wb_ctx *wb_ctx, ta_vo_wb_frame *frame);

参数说明

参数类型说明
wb_ctxta_vo_wb_ctx *回写设备上下文指针
frameta_vo_wb_frame *要释放的回写帧结构体指针

返回值

返回值描述
0成功
-1失败: wb_ctx、framelayer_ctxNULL

6.6.5 ta-vo 结构体及相关字段说明

1. ta_vo_chn_ctx

说明

视频通道上下文结构体,封装了单个视频输出通道的所有运行时状态和配置信息,包括帧数据、属性设置、定时器及绑定关系等。

定义

typedef struct {
ta_vo_frame *frame;
ta_vo_chn chn;
ta_vo_chn_attr *chn_attr;
int frame_processed;
int timer_fd;
void *layer_ctx;
} ta_vo_chn_ctx;

成员

字段名类型说明
frameta_vo_frame *指向当前视频帧的指针
chnta_vo_chn通道编号。取值范围:[0, TA_VO_MAX_CHN_NUMS]
chn_attrta_vo_chn_attr *指向通道属性的指针
frame_processedint帧处理状态标志(0:未处理, 1:已处理)
timer_fdint定时器文件描述符,用于帧率同步。当 chn_attr->fps 大于 0 时由 ta_vo_chn_set_attr 自动创建
layer_ctxvoid *指向绑定图层的上下文指针。通过 ta_vo_chn_bind_to_layer 函数设置

2. ta_vo_chn

说明

定义通道号

定义

typedef unsigned int ta_vo_chn;

3. ta_vo_layer_ctx

说明

视频图层上下文结构体,封装了单个显示图层的完整硬件和软件状态,包括帧缓冲设备管理、内存映射、双缓冲机制、通道绑定关系及显示线程控制等。

定义

typedef struct {
int fd;
int fmt;
ta_vo_layer virtual_layer_id;
unsigned char *smem_start;
unsigned long smem_start_phys_addr;
int buffer_nums;
ta_vo_frame *frame[MAX_QUEUES];
unsigned int disp_blk_id[MAX_QUEUES];
unsigned long disp_blk_size;
int enabled;
ta_vo_dev_ctx *dev_ctx;
TA_AVDictionaryEntry elems[MAX_QUEUES];
TA_AVDictionary metadata[MAX_QUEUES];
struct fb_fix_screeninfo fix; // fb固定参数
pthread_t show_thread_id;
int timer_fd;
ta_vo_layer_attr attr;
char str_blk_id[MAX_QUEUES][TA_VO_LAYER_MAX][16];
int chn_nums;
ta_vo_chn_ctx *chn_ctx[TA_VO_CHN_MAX];
unsigned int fb_size;
int idle_buf_id;
void *wb_ctx;
volatile unsigned int back_buf_id;
volatile unsigned int front_buf_id;
volatile unsigned int buf_locked[MAX_QUEUES];
pthread_cond_t cond;
volatile unsigned int dev_can_continue;
volatile unsigned int wb_can_continue;
pthread_mutex_t mutex;
pthread_t dev_show_thread_id;
} ta_vo_layer_ctx;

成员

字段名类型说明
fdint帧缓冲设备文件描述符。取值:大于 0 表示有效,小于等于 0 表示无效或未打开
fmtint像素格式标识。取值:TA_AV_PIX_FMT_NV12TA_AV_PIX_FMT_ARGBTA_AV_PIX_FMT_RGB24
virtual_layer_idta_vo_layer虚拟图层 ID(如 TA_VO_LAYER_VIDEO_0
smem_startunsigned char *显示缓冲区的虚拟起始地址。通过 taco_sys_mmap_noncache 获得
smem_start_phys_addrunsigned long显示缓冲区的物理起始地址。通过 taco_sys_handle2_phys_addr 转换
buffer_numsint缓冲区数量(双缓冲=2,三缓冲=3)
frameta_vo_frame *[MAX_QUEUES]帧数据指针数组
disp_blk_idunsigned int[MAX_QUEUES]显示内存块 ID 数组,由 taco_sys_get_block 分配
disp_blk_sizeunsigned long显示内存块大小
enabledint图层启用状态(0:禁用, 1:启用)
dev_ctxta_vo_dev_ctx *指向绑定设备的上下文指针。通过 ta_vo_dev_bind_to_layer 设置
elemsTA_AVDictionaryEntry[MAX_QUEUES]元数据条目结构体数组,存储键值对形式的元数据(如内存块 ID、物理地址等)
metadataTA_AVDictionary[MAX_QUEUES]元数据字典结构体数组,管理元数据条目集合
fixstruct fb_fix_screeninfo帧缓冲设备固定参数。重要字段:smem_startsmem_lenline_length。获取方式:ioctl(fd, FBIOGET_FSCREENINFO, &fix)
show_thread_idpthread_t显示线程 ID。创建时机:图层启用且 use_ta_cv=1 时自动创建
timer_fdint定时器文件描述符,用于帧率同步。时钟类型:CLOCK_MONOTONIC 单调时钟
attrta_vo_layer_attr图层属性。设置方式:通过 ta_vo_layer_set_attr 设置
str_blk_idchar[MAX_QUEUES][TA_VO_LAYER_MAX][16]内存块 ID 字符串表示,格式为十进制数字字符串
chn_numsint绑定到该图层的通道数量。取值范围:[0, TA_VO_CHN_MAX]
chn_ctxta_vo_chn_ctx *[TA_VO_CHN_MAX]绑定通道的指针数组,以通道号作为数组索引
fb_sizeunsigned int单个显示缓冲区的字节大小
idle_buf_idint空闲缓冲区索引
wb_ctxvoid *回写上下文指针
back_buf_idvolatile unsigned int后缓冲区索引(当前可写入)
front_buf_idvolatile unsigned int前缓冲区索引(当前显示)
buf_lockedvolatile unsigned int[MAX_QUEUES]缓冲区锁定标志数组
condpthread_cond_t条件变量(用于线程同步)
dev_can_continuevolatile unsigned int设备是否可继续运行的标志
wb_can_continuevolatile unsigned int回写是否可继续的标志
mutexpthread_mutex_t图层互斥锁(保护共享资源)
dev_show_thread_idpthread_t设备显示线程 ID

4. ta_vo_chn_attr

说明

通道属性配置结构体,用于定义视频输出通道的显示参数和行为特性。通过 ta_vo_chn_set_attr 函数设置,控制通道的视频显示位置、帧率控制和图形处理模式。

定义

typedef struct {
int x;
int y;
int width;
int height;
int fps;
} ta_vo_chn_attr;

成员

字段名类型说明
xint通道显示区域左上角 X 坐标(像素)
yint通道显示区域左上角 Y 坐标(像素)
widthint通道显示区域宽度(像素)
heightint通道显示区域高度(像素)
fpsint帧率控制(帧/秒):0 表示不限制;1–60 为常见范围;大于 60 为高帧率应用,需硬件支持

5. ta_vo_frame

说明

视频帧数据结构体,基于FFmpeg的AVFrame结构扩展,用于承载视频图像数据及相关的元信息。该结构体作为视频数据在VO模块中的统一表示形式,支持多种像素格式、时间戳同步、内存管理和元数据传递。

定义

typedef struct {
unsigned char *frame;
ta_avframe_t *av_frame;
} ta_vo_frame;

核心成员

字段名类型说明
frameunsigned char *原始帧数据指针(通常指向 YUV 平面)
av_frameta_avframe_t *FFmpeg AVFrame 扩展结构体指针,携带时间戳、格式等元数据

6. ta_vo_dev_ctx

说明

设备上下文结构体,作为物理显示设备的软件抽象,封装了设备类型标识和运行参数。该结构体是连接图层与硬件设备的关键桥梁,负责管理设备级别的显示控制、时序配置和资源分配。

定义

typedef struct {
ta_vo_dev dev;
ta_vo_dev_attr attr;
} ta_vo_dev_ctx;

成员

字段名类型说明
devta_vo_dev设备类型标识
attrta_vo_dev_attr设备属性结构体

7. ta_vo_dev

说明

设备类型枚举,定义系统支持的物理显示硬件类型。每个枚举值对应一种特定的显示硬件单元,用于创建设备上下文时指定目标硬件。该枚举确保类型安全,防止无效设备类型的使用,同时为系统扩展提供清晰的版本管理。

定义

typedef enum {
TA_VO_DEV_IDS = 0,
TA_VO_DEV_USB_TO_HDMI = 1,
TA_VO_DEV_MAX = 2
} ta_vo_dev;

成员

枚举值数值说明
TA_VO_DEV_IDS0IDS叠加层显示设备
TA_VO_DEV_USB_TO_HDMI1USB转HDMI显示设备
TA_VO_DEV_MAX2设备类型最大值,用于范围检查

8. ta_vo_dev_attr

说明

设备属性配置结构体,定义物理显示设备的运行时参数和行为特性。这些属性控制设备如何将图层内容输出到物理显示器,包括时序控制、图像处理和质量调节等功能。通过精细的设备属性配置,可以在不同硬件上实现一致的显示效果。

定义

typedef struct {
int fps;
int hw_layer_nums;
hw_layer_attr layer[TA_VO_MAX_LAYER_NUMS];
int scaler_width;
int scaler_height;
int scaler_x;
int scaler_y;
int colorkey_enable;
int colorkey_x;
int colorkey_y;
int colorkey_width;
int colorkey_height;
} ta_vo_dev_attr;

成员

字段名类型说明
fpsint设备输出帧率(帧/秒),0=自适应
hw_layer_numsint硬件图层数量
layerhw_layer_attr[TA_VO_MAX_LAYER_NUMS]各硬件图层属性数组
scaler_widthint硬件缩放器输出宽度(像素)
scaler_heightint硬件缩放器输出高度(像素)
scaler_xint缩放器输出区域 X 坐标
scaler_yint缩放器输出区域 Y 坐标
colorkey_enableint颜色键功能开关(0=关闭,1=启用)
colorkey_xint颜色键区域左上角 X 坐标
colorkey_yint颜色键区域左上角 Y 坐标
colorkey_widthint颜色键区域宽度(像素)
colorkey_heightint颜色键区域高度(像素)

9. ta_vo_layer_attr

说明

图层属性配置结构体,定义视频/图形图层的显示特性、处理模式、缓冲区管理和高级合成功能。该结构体控制图层如何接收、处理和输出视觉内容,是决定显示效果和性能的关键配置。

定义

typedef struct {
int format;
unsigned char *buf;
fb_format buf_format;
void *wb_ctx;
int use_av_frame;
int hw_layer_id;
int queue_size;
int width;
int height;
int fps;
} ta_vo_layer_attr;

成员

字段名类型说明
formatint输入像素格式(如 NV12、ARGB)
bufunsigned char *显示缓冲区指针(物理连续,64字节对齐)
buf_formatfb_format帧缓冲格式(RGB565、ARGB8888 等)
wb_ctxvoid *回写上下文指针(用于图层内容捕获)
use_av_frameint是否使用 AVFrame 传递数据(0/1)
hw_layer_idint硬件图层 ID(对应硬件资源)
queue_sizeint帧队列大小(缓冲区数量)
widthint图层宽度(像素)
heightint图层高度(像素)
fpsint图层帧率(帧/秒),0=不限

10. ta_vo_layer

说明

图层类型枚举,定义系统中可用的显示图层标识。每个枚举值对应一个逻辑显示平面,用于区分不同类型的显示内容和处理特性。系统通过此枚举管理有限的可视化资源,确保不同类型的视觉内容能够合理分配到适当的硬件平面。

定义

typedef enum {
TA_VO_LAYER_VIDEO_0 = 0,
TA_VO_LAYER_GRAPH_0 = 1,
TA_VO_LAYER_MAX = 2
} ta_vo_layer;

成员

枚举值数值说明
TA_VO_LAYER_VIDEO_00视频图层0 - 主要视频显示平面
TA_VO_LAYER_GRAPH_01图形图层0 - 主要图形界面平面
TA_VO_LAYER_MAX2图层类型最大值 - 边界标识

11. ta_vo_wb

说明

回写设备标识类型,用于唯一标识视频回写(Write Back)设备实例。回写设备负责从显示流水线捕获视频帧数据,供录制、分析、编码或远程传输等应用使用。该类型本质上是无符号整数的别名,提供了类型安全性和代码可读性。

定义

typedef unsigned int ta_vo_wb;

12. ta_vo_wb_src

说明

回写数据源配置结构体,用于指定回写操作的具体数据来源。当回写源类型为图层时,该结构体提供目标图层的标识信息,确保回写设备从正确的位置捕获视频数据。

定义

typedef struct {
ta_vo_layer layer;
} ta_vo_wb_src;

成员

字段名类型说明
layerta_vo_layer目标图层标识,指定从哪个图层捕获显示内容

13. TA_VO_CHN_MAX

说明

视频通道数量上限宏定义,用于限定系统中同时可用的最大视频通道数量。该常量是系统资源规划、内存分配和运行时验证的关键参数,确保视频输出系统在已知的资源约束下稳定运行。

定义

#define TA_VO_CHN_MAX (16)
14. ta_vo_wb_ctx

说明

视频回写设备上下文结构体,封装了回写设备的所有运行时状态、属性配置、线程同步机制及帧数据队列管理。该结构体作为回写设备的核心控制块,负责协调从显示流水线捕获帧数据并传递给后续处理模块的完整流程。

定义

typedef struct {
ta_vo_wb_attr attr;
ta_vo_wb wb;
pthread_mutex_t wb_mutex;
pthread_mutex_t ref_lock;
int enable;
int ref_cnt;
pthread_cond_t cond;
void *layer_ctx;
pthread_t thread;
void *frame_queue[MAX_QUEUES];
int queue_size;
int queue_head;
int queue_tail;
int queue_count;
} ta_vo_wb_ctx;

成员

字段名类型说明
attrta_vo_wb_attr回写设备属性配置结构体
wbta_vo_wb回写设备标识
wb_mutexpthread_mutex_t回写设备操作互斥锁,保护设备状态的并发访问
ref_lockpthread_mutex_t引用计数锁,保护 ref_cnt 的原子性操作
enableint回写设备启用状态(0:禁用, 1:启用)
ref_cntint引用计数,用于管理上下文的生命周期
condpthread_cond_t线程条件变量,用于帧队列的同步等待
layer_ctxvoid *指向绑定图层的上下文指针
threadpthread_t回写处理线程ID
frame_queuevoid *[MAX_QUEUES]帧数据指针队列,用于存储捕获的视频帧
queue_sizeint队列总大小
queue_headint队列头索引(读位置)
queue_tailint队列尾索引(写位置)
queue_countint当前队列中的帧数

15. ta_vo_wb_attr

说明

回写设备属性配置结构体,定义视频回写设备的数据来源和工作模式。通过该结构体指定回写操作是从特定图层捕获还是从设备输出端捕获,是配置回写设备的核心参数。

定义

typedef struct {
ta_vo_wb_src src;
} ta_vo_wb_attr;

成员

字段名类型说明
srcta_vo_wb_src回写数据源配置,指定数据来源类型及具体标识

16. ta_vo_wb_frame

说明

回写视频帧数据结构体,用于承载从显示流水线捕获的完整视频帧信息。该结构体包含图像数据的虚拟/物理地址、尺寸格式、 stride 信息及引用计数管理,是回写数据在系统中传递的标准载体。

定义

typedef struct {
void *pVirAddr[3];
unsigned long u64PhyAddr[3];
int width;
int height;
int format;
int stride[3];
int ref_cnt;
pthread_mutex_t ref_lock;
void *buf;
int layer_buf_id;
unsigned int len;
int id;
ta_avframe_t *av_frame;
} ta_vo_wb_frame;

成员

字段名类型说明
pVirAddrvoid *[3]虚拟地址数组(Y/U/V 或 Y/UV 平面)
u64PhyAddrunsigned long[3]物理地址数组(可选,用于硬件编码)
widthint帧宽度(像素)
heightint帧高度(像素)
formatint像素格式标识
strideint[3]每行字节数数组(stride),包含各平面的行跨度
ref_cntint引用计数,用于管理帧数据的生命周期
ref_lockpthread_mutex_t引用计数锁,保护 ref_cnt 的原子性操作
bufvoid *用户自定义数据指针,可用于传递附加信息
layer_buf_idint图层缓冲区ID
lenunsigned int数据总长度(字节)
idint帧标识ID

七、 附录

A 术语解释

术语说明
AVDictionary是一个键值对存储工具,类似于 C++ 中的 map,FFmpeg 中有很多 API 通过它来传递参数。
Frame在视频处理领域,帧(Frame)表示构成视频(Video)的单个静止画面,视频采集、存储、传输和处理一般都是以帧为基本数据单位的。在计算机内存中,用来临时性存储一帧图像数据的区域常被称为帧缓存(Frame Buffer),简称帧存。
JPEG英文 Joint Photographic Experts Group 的缩写,是一种常见的图像压缩格式,它采用有损压缩方法以减小文件大小。按照解码方式可分成基线(Baseline)格式和渐进(Progressive)格式两种。在基线格式下,图像的加载是按照从上到下、从左到右的顺序一次加载完成。在渐进格式下,图像的加载是分阶段完成的,先加载低频信息展示整体概貌,再加载高频信息补充细节,最终获得完整清晰的图像。
Packed打包格式,是指一种图像存储格式,特点是一个像素的多个颜色通道依次紧密存储,通道之间没有填充,然后下一个像素依次紧密存储,像素之间没有填充。
Planar平面格式,是一种图像存储格式,特点是按颜色通道组织存储,所有像素的同名颜色通道存储在一起构成一个数据平面。
RTSP实时流传输协议(Real Time Streaming Protocol),是在 RFC 2326 标准中定义的网络协议,描述了一对应用程序如何通过 IP 网络传送多媒体数据。在体系结构上,RTSP 使用 RTP 实现数据传输,使用 RTCP 实现传输控制。
RVVRISC-V Vector extension,RISC-V 架构的向量扩展,即“V”扩展,它定义了一组 SIMD 指令用于支持向量计算,能够支持从小型嵌入式系统到大型高性能计算环境的广泛应用。关于 RVV 规范已经有多个正式版本,包括 2019 年 12 月发布的 0.8 版本,目前最新的是 2021 年 9 月发布的 1.0 版本。
SPPStandalone Pre-Processing unit,独立预处理单元,是 EA65xx 芯片中支持的一个硬件处理单元,可以提供颜色空间变换(CSC)、缩放(scaling)、裁剪(crop)等常用视频处理操作,其中的 PP 既可以理解为预处理(NPU 推理之前),也可以理解为后处理(Post-Processing,视频解码之后)。
PPUParallel Processing Unit,EA65xx 芯片中位于 NPU 功能簇的一个硬件处理单元,可以通过 OpenVX 框架进行编程,从而提供新的算子。
Stride跨距,是指一笔数据在内存中实际占用的字节数。在图像处理领域有 pixel stride 和 line stride 概念,后者是指图像在存储时一行像素所占用的字节数。出于对齐要求,line stride 可能大于图像宽度(picture width),多出的部分称为填充数据(padding)。
VDEC硬件解码模块,VDEC 解码模块支持 H.264/H.265/JPEG/MJPEG 解码.
VENC硬件编码模块,VENC 编码模块支持 H.264/JPEG/MJPEG 编码.
NPU神经网络处理单元,是一种专为深度学习和神经网络运算设计的处理器。它通过高度定制化的计算单元、存储结构和数据流调度机制,实现对深度学习模型中的特征提取、权重更新、激活函数计算等操作的加速。
MMU一种计算机硬件设备,在计算机系统中提供虚拟地址到物理地址转换、内存保护、高速缓存控制等功能。
NN神经网络,本文中泛指与神经网络相关的算法模型和配套技术。
BT.601BT.601 是国际电信联盟(ITU-R)制定的一个视频信号标准,全称为 Rec. ITU-R BT.601(原 CCIR 601),主要定义了标清数字视频的编码方式、色彩空间和信号格式。
SDKSoftware Development Kit,软件开发套件,是一套包含了编译器、调试器和一系列用于开发特定平台、系统或编程语言应用的工具。SDK 通常由硬件平台、操作系统或编程语言的制造商提供,它为开发者提供了一系列必要的工具和库,以便更快速、高效地开发应用程序。
TACO特普斯微推出的一种显示软件开发套件(SDK),用于支持开发者在特普斯微边缘计算处理器平台上开发部署视频显示应用。
TPS公司名特普斯微(TOPSFuture)的缩写,在 SDK 中经常用做前缀。